obsidian-integration-testing 8.0.1 → 8.1.1

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.
Files changed (65) hide show
  1. package/README.md +23 -4
  2. package/dist/lib/cjs/cli.cjs +29 -8
  3. package/dist/lib/cjs/cli.d.cts +2 -1
  4. package/dist/lib/cjs/connect-to-cdp.cjs +17 -11
  5. package/dist/lib/cjs/connect-to-cdp.d.cts +35 -3
  6. package/dist/lib/cjs/context-provider.cjs +1 -1
  7. package/dist/lib/cjs/context-provider.d.cts +1 -1
  8. package/dist/lib/cjs/global-setup-core.cjs +17 -5
  9. package/dist/lib/cjs/global-setup-core.d.cts +11 -1
  10. package/dist/lib/cjs/incompatible-installer-version-error.cjs +52 -0
  11. package/dist/lib/cjs/incompatible-installer-version-error.d.cts +44 -0
  12. package/dist/lib/cjs/index.cjs +13 -1
  13. package/dist/lib/cjs/index.d.cts +7 -0
  14. package/dist/lib/cjs/installer-compatibility.cjs +64 -0
  15. package/dist/lib/cjs/installer-compatibility.d.cts +75 -0
  16. package/dist/lib/cjs/library.cjs +1 -1
  17. package/dist/lib/cjs/namespace-bootstrap.cjs +16 -7
  18. package/dist/lib/cjs/obsidian-installer.cjs +7 -4
  19. package/dist/lib/cjs/obsidian-metadata.cjs +1811 -0
  20. package/dist/lib/cjs/obsidian-metadata.d.cts +56 -0
  21. package/dist/lib/cjs/renderer-boot-detection.cjs +49 -0
  22. package/dist/lib/cjs/renderer-boot-detection.d.cts +83 -0
  23. package/dist/lib/cjs/renderer-failed-to-initialize-error.cjs +41 -0
  24. package/dist/lib/cjs/renderer-failed-to-initialize-error.d.cts +23 -0
  25. package/dist/lib/cjs/transport-desktop-cdp.cjs +85 -3
  26. package/dist/lib/cjs/transport-desktop-cdp.d.cts +55 -1
  27. package/dist/lib/cjs/transport-factory.cjs +76 -21
  28. package/dist/lib/cjs/transport-factory.d.cts +1 -1
  29. package/dist/lib/cjs/transport-options.cjs +1 -1
  30. package/dist/lib/cjs/transport-options.d.cts +37 -4
  31. package/dist/lib/cjs/visibility.cjs +10 -2
  32. package/dist/lib/cjs/visibility.d.cts +27 -8
  33. package/dist/lib/esm/cli.d.mts +2 -1
  34. package/dist/lib/esm/cli.mjs +29 -8
  35. package/dist/lib/esm/connect-to-cdp.d.mts +35 -3
  36. package/dist/lib/esm/connect-to-cdp.mjs +17 -11
  37. package/dist/lib/esm/context-provider.d.mts +1 -1
  38. package/dist/lib/esm/context-provider.mjs +1 -1
  39. package/dist/lib/esm/global-setup-core.d.mts +11 -1
  40. package/dist/lib/esm/global-setup-core.mjs +15 -4
  41. package/dist/lib/esm/incompatible-installer-version-error.d.mts +44 -0
  42. package/dist/lib/esm/incompatible-installer-version-error.mjs +28 -0
  43. package/dist/lib/esm/index.d.mts +7 -0
  44. package/dist/lib/esm/index.mjs +9 -1
  45. package/dist/lib/esm/installer-compatibility.d.mts +75 -0
  46. package/dist/lib/esm/installer-compatibility.mjs +40 -0
  47. package/dist/lib/esm/library.mjs +1 -1
  48. package/dist/lib/esm/namespace-bootstrap.mjs +16 -7
  49. package/dist/lib/esm/obsidian-installer.mjs +7 -4
  50. package/dist/lib/esm/obsidian-metadata.d.mts +56 -0
  51. package/dist/lib/esm/obsidian-metadata.mjs +1787 -0
  52. package/dist/lib/esm/renderer-boot-detection.d.mts +83 -0
  53. package/dist/lib/esm/renderer-boot-detection.mjs +23 -0
  54. package/dist/lib/esm/renderer-failed-to-initialize-error.d.mts +23 -0
  55. package/dist/lib/esm/renderer-failed-to-initialize-error.mjs +17 -0
  56. package/dist/lib/esm/transport-desktop-cdp.d.mts +55 -1
  57. package/dist/lib/esm/transport-desktop-cdp.mjs +89 -3
  58. package/dist/lib/esm/transport-factory.d.mts +1 -1
  59. package/dist/lib/esm/transport-factory.mjs +76 -21
  60. package/dist/lib/esm/transport-options.d.mts +37 -4
  61. package/dist/lib/esm/visibility.d.mts +27 -8
  62. package/dist/lib/esm/visibility.mjs +8 -2
  63. package/dist/obsidian-integration-testing-8.1.1.tgz +0 -0
  64. package/package.json +2 -3
  65. package/dist/obsidian-integration-testing-8.0.1.tgz +0 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * Pure detection of a terminal "dead boot" of the owned Obsidian renderer, plus
5
+ * resolving the fast-fail grace window from the transport options. Kept separate
6
+ * from the integration-only `transport-desktop-cdp` (which drives real CDP and is
7
+ * excluded from unit tests) so the verdict logic and default resolution stay
8
+ * unit-testable.
9
+ *
10
+ * When an Obsidian asar cannot run on the launched Electron shell (the installer
11
+ * version is too old for that app version), the renderer loads `index.html`
12
+ * (`document.readyState` reaches `'complete'`) but the app never bootstraps:
13
+ * `document.body` stays empty and `window.app` remains `undefined` — visually a
14
+ * black screen. The owned-vault readiness poll cannot tell this terminal state
15
+ * apart from "still loading", so without a detector it waits out the whole
16
+ * readiness timeout before failing. This module encodes the signal that
17
+ * distinguishes the two: once the renderer has been `complete` for a short grace
18
+ * window with no `window.app` and an empty `<body>`, it is dead, not slow.
19
+ */
20
+ import type { ObsidianCdpTransportOptions } from './transport-options.mjs';
21
+ /**
22
+ * Default for {@link ObsidianCdpTransportOptions.deadBootGraceInMilliseconds}.
23
+ */
24
+ export declare const DEFAULT_DEAD_BOOT_GRACE_IN_MILLISECONDS = 10000;
25
+ /**
26
+ * Parameters for {@link checkRendererBootState}.
27
+ */
28
+ export interface CheckRendererBootStateParams extends RendererBootObservation {
29
+ /**
30
+ * Whether the bootstrap grace window has elapsed since the renderer first
31
+ * reached `document.readyState` `'complete'`. The `'dead'` verdict is withheld
32
+ * until this is `true` so a genuinely slow boot is never misjudged.
33
+ */
34
+ readonly hasGraceElapsed: boolean;
35
+ }
36
+ /**
37
+ * A sample of the owned renderer's bootstrap state, taken from the vault page
38
+ * target via a single CDP evaluation.
39
+ */
40
+ export interface RendererBootObservation {
41
+ /**
42
+ * `document.body.childElementCount` in the vault renderer (`0` when `body` is
43
+ * absent). A dead boot leaves the body empty; a slow-but-valid boot renders at
44
+ * least a loading shell.
45
+ */
46
+ readonly bodyChildElementCount: number;
47
+ /** Whether `window.app` is defined in the vault renderer. */
48
+ readonly hasWindowApp: boolean;
49
+ /** Whether the vault renderer's `document.readyState` is `'complete'`. */
50
+ readonly isDocumentComplete: boolean;
51
+ }
52
+ /**
53
+ * Verdict from {@link checkRendererBootState}: `'dead'` when the renderer has
54
+ * terminally failed to initialize, `'pending'` when it may still be booting.
55
+ */
56
+ export type RendererBootVerdict = 'dead' | 'pending';
57
+ /**
58
+ * Decides whether the owned renderer has terminally failed to initialize.
59
+ *
60
+ * The verdict is `'dead'` only when all of the following hold: the grace window
61
+ * has elapsed, `window.app` is still undefined, the document is `'complete'`,
62
+ * and `<body>` is empty. This is exactly the observed incompatible-shell state
63
+ * (an asar that cannot run on the launched Electron), and it cannot be reached
64
+ * by a healthy boot — `window.app` is defined early, and a slow boot renders a
65
+ * non-empty loading shell — so there is no false-positive path on a valid boot.
66
+ *
67
+ * @param params - The sampled observation plus whether the grace has elapsed.
68
+ * @returns `'dead'` when the renderer is terminally dead, otherwise `'pending'`.
69
+ */
70
+ export declare function checkRendererBootState(params: CheckRendererBootStateParams): RendererBootVerdict;
71
+ /**
72
+ * Resolves the dead-boot fast-fail grace window, applying the default when the
73
+ * option is omitted.
74
+ *
75
+ * This bounds how long the owned-vault readiness poll waits — after the renderer
76
+ * first reaches `document.readyState` `'complete'` — before concluding the boot
77
+ * is dead (see {@link checkRendererBootState}). A value of `0` disables fast-fail
78
+ * entirely, restoring the plain wait-out-the-readiness-timeout behavior.
79
+ *
80
+ * @param options - The desktop CDP transport options (or the relevant slice).
81
+ * @returns The grace window in milliseconds.
82
+ */
83
+ export declare function resolveDeadBootGraceInMilliseconds(options?: Pick<ObsidianCdpTransportOptions, 'deadBootGraceInMilliseconds'>): number;
@@ -0,0 +1,23 @@
1
+ const DEFAULT_DEAD_BOOT_GRACE_IN_MILLISECONDS = 1e4;
2
+ function checkRendererBootState(params) {
3
+ const { bodyChildElementCount, hasGraceElapsed, hasWindowApp, isDocumentComplete } = params;
4
+ if (hasWindowApp) {
5
+ return "pending";
6
+ }
7
+ if (!hasGraceElapsed) {
8
+ return "pending";
9
+ }
10
+ if (isDocumentComplete && bodyChildElementCount === 0) {
11
+ return "dead";
12
+ }
13
+ return "pending";
14
+ }
15
+ function resolveDeadBootGraceInMilliseconds(options) {
16
+ return options?.deadBootGraceInMilliseconds ?? DEFAULT_DEAD_BOOT_GRACE_IN_MILLISECONDS;
17
+ }
18
+ export {
19
+ DEFAULT_DEAD_BOOT_GRACE_IN_MILLISECONDS,
20
+ checkRendererBootState,
21
+ resolveDeadBootGraceInMilliseconds
22
+ };
23
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3JlbmRlcmVyLWJvb3QtZGV0ZWN0aW9uLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUHVyZSBkZXRlY3Rpb24gb2YgYSB0ZXJtaW5hbCBcImRlYWQgYm9vdFwiIG9mIHRoZSBvd25lZCBPYnNpZGlhbiByZW5kZXJlciwgcGx1c1xuICogcmVzb2x2aW5nIHRoZSBmYXN0LWZhaWwgZ3JhY2Ugd2luZG93IGZyb20gdGhlIHRyYW5zcG9ydCBvcHRpb25zLiBLZXB0IHNlcGFyYXRlXG4gKiBmcm9tIHRoZSBpbnRlZ3JhdGlvbi1vbmx5IGB0cmFuc3BvcnQtZGVza3RvcC1jZHBgICh3aGljaCBkcml2ZXMgcmVhbCBDRFAgYW5kIGlzXG4gKiBleGNsdWRlZCBmcm9tIHVuaXQgdGVzdHMpIHNvIHRoZSB2ZXJkaWN0IGxvZ2ljIGFuZCBkZWZhdWx0IHJlc29sdXRpb24gc3RheVxuICogdW5pdC10ZXN0YWJsZS5cbiAqXG4gKiBXaGVuIGFuIE9ic2lkaWFuIGFzYXIgY2Fubm90IHJ1biBvbiB0aGUgbGF1bmNoZWQgRWxlY3Ryb24gc2hlbGwgKHRoZSBpbnN0YWxsZXJcbiAqIHZlcnNpb24gaXMgdG9vIG9sZCBmb3IgdGhhdCBhcHAgdmVyc2lvbiksIHRoZSByZW5kZXJlciBsb2FkcyBgaW5kZXguaHRtbGBcbiAqIChgZG9jdW1lbnQucmVhZHlTdGF0ZWAgcmVhY2hlcyBgJ2NvbXBsZXRlJ2ApIGJ1dCB0aGUgYXBwIG5ldmVyIGJvb3RzdHJhcHM6XG4gKiBgZG9jdW1lbnQuYm9keWAgc3RheXMgZW1wdHkgYW5kIGB3aW5kb3cuYXBwYCByZW1haW5zIGB1bmRlZmluZWRgIFx1MjAxNCB2aXN1YWxseSBhXG4gKiBibGFjayBzY3JlZW4uIFRoZSBvd25lZC12YXVsdCByZWFkaW5lc3MgcG9sbCBjYW5ub3QgdGVsbCB0aGlzIHRlcm1pbmFsIHN0YXRlXG4gKiBhcGFydCBmcm9tIFwic3RpbGwgbG9hZGluZ1wiLCBzbyB3aXRob3V0IGEgZGV0ZWN0b3IgaXQgd2FpdHMgb3V0IHRoZSB3aG9sZVxuICogcmVhZGluZXNzIHRpbWVvdXQgYmVmb3JlIGZhaWxpbmcuIFRoaXMgbW9kdWxlIGVuY29kZXMgdGhlIHNpZ25hbCB0aGF0XG4gKiBkaXN0aW5ndWlzaGVzIHRoZSB0d286IG9uY2UgdGhlIHJlbmRlcmVyIGhhcyBiZWVuIGBjb21wbGV0ZWAgZm9yIGEgc2hvcnQgZ3JhY2VcbiAqIHdpbmRvdyB3aXRoIG5vIGB3aW5kb3cuYXBwYCBhbmQgYW4gZW1wdHkgYDxib2R5PmAsIGl0IGlzIGRlYWQsIG5vdCBzbG93LlxuICovXG5cbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5DZHBUcmFuc3BvcnRPcHRpb25zIH0gZnJvbSAnLi90cmFuc3BvcnQtb3B0aW9ucy5tanMnO1xuXG4vKipcbiAqIERlZmF1bHQgZm9yIHtAbGluayBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMuZGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzfS5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfREVBRF9CT09UX0dSQUNFX0lOX01JTExJU0VDT05EUyA9IDEwMDAwO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBjaGVja1JlbmRlcmVyQm9vdFN0YXRlfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaGVja1JlbmRlcmVyQm9vdFN0YXRlUGFyYW1zIGV4dGVuZHMgUmVuZGVyZXJCb290T2JzZXJ2YXRpb24ge1xuICAvKipcbiAgICogV2hldGhlciB0aGUgYm9vdHN0cmFwIGdyYWNlIHdpbmRvdyBoYXMgZWxhcHNlZCBzaW5jZSB0aGUgcmVuZGVyZXIgZmlyc3RcbiAgICogcmVhY2hlZCBgZG9jdW1lbnQucmVhZHlTdGF0ZWAgYCdjb21wbGV0ZSdgLiBUaGUgYCdkZWFkJ2AgdmVyZGljdCBpcyB3aXRoaGVsZFxuICAgKiB1bnRpbCB0aGlzIGlzIGB0cnVlYCBzbyBhIGdlbnVpbmVseSBzbG93IGJvb3QgaXMgbmV2ZXIgbWlzanVkZ2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgaGFzR3JhY2VFbGFwc2VkOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEEgc2FtcGxlIG9mIHRoZSBvd25lZCByZW5kZXJlcidzIGJvb3RzdHJhcCBzdGF0ZSwgdGFrZW4gZnJvbSB0aGUgdmF1bHQgcGFnZVxuICogdGFyZ2V0IHZpYSBhIHNpbmdsZSBDRFAgZXZhbHVhdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZW5kZXJlckJvb3RPYnNlcnZhdGlvbiB7XG4gIC8qKlxuICAgKiBgZG9jdW1lbnQuYm9keS5jaGlsZEVsZW1lbnRDb3VudGAgaW4gdGhlIHZhdWx0IHJlbmRlcmVyIChgMGAgd2hlbiBgYm9keWAgaXNcbiAgICogYWJzZW50KS4gQSBkZWFkIGJvb3QgbGVhdmVzIHRoZSBib2R5IGVtcHR5OyBhIHNsb3ctYnV0LXZhbGlkIGJvb3QgcmVuZGVycyBhdFxuICAgKiBsZWFzdCBhIGxvYWRpbmcgc2hlbGwuXG4gICAqL1xuICByZWFkb25seSBib2R5Q2hpbGRFbGVtZW50Q291bnQ6IG51bWJlcjtcblxuICAvKiogV2hldGhlciBgd2luZG93LmFwcGAgaXMgZGVmaW5lZCBpbiB0aGUgdmF1bHQgcmVuZGVyZXIuICovXG4gIHJlYWRvbmx5IGhhc1dpbmRvd0FwcDogYm9vbGVhbjtcblxuICAvKiogV2hldGhlciB0aGUgdmF1bHQgcmVuZGVyZXIncyBgZG9jdW1lbnQucmVhZHlTdGF0ZWAgaXMgYCdjb21wbGV0ZSdgLiAqL1xuICByZWFkb25seSBpc0RvY3VtZW50Q29tcGxldGU6IGJvb2xlYW47XG59XG5cbi8qKlxuICogVmVyZGljdCBmcm9tIHtAbGluayBjaGVja1JlbmRlcmVyQm9vdFN0YXRlfTogYCdkZWFkJ2Agd2hlbiB0aGUgcmVuZGVyZXIgaGFzXG4gKiB0ZXJtaW5hbGx5IGZhaWxlZCB0byBpbml0aWFsaXplLCBgJ3BlbmRpbmcnYCB3aGVuIGl0IG1heSBzdGlsbCBiZSBib290aW5nLlxuICovXG5leHBvcnQgdHlwZSBSZW5kZXJlckJvb3RWZXJkaWN0ID0gJ2RlYWQnIHwgJ3BlbmRpbmcnO1xuXG4vKipcbiAqIERlY2lkZXMgd2hldGhlciB0aGUgb3duZWQgcmVuZGVyZXIgaGFzIHRlcm1pbmFsbHkgZmFpbGVkIHRvIGluaXRpYWxpemUuXG4gKlxuICogVGhlIHZlcmRpY3QgaXMgYCdkZWFkJ2Agb25seSB3aGVuIGFsbCBvZiB0aGUgZm9sbG93aW5nIGhvbGQ6IHRoZSBncmFjZSB3aW5kb3dcbiAqIGhhcyBlbGFwc2VkLCBgd2luZG93LmFwcGAgaXMgc3RpbGwgdW5kZWZpbmVkLCB0aGUgZG9jdW1lbnQgaXMgYCdjb21wbGV0ZSdgLFxuICogYW5kIGA8Ym9keT5gIGlzIGVtcHR5LiBUaGlzIGlzIGV4YWN0bHkgdGhlIG9ic2VydmVkIGluY29tcGF0aWJsZS1zaGVsbCBzdGF0ZVxuICogKGFuIGFzYXIgdGhhdCBjYW5ub3QgcnVuIG9uIHRoZSBsYXVuY2hlZCBFbGVjdHJvbiksIGFuZCBpdCBjYW5ub3QgYmUgcmVhY2hlZFxuICogYnkgYSBoZWFsdGh5IGJvb3QgXHUyMDE0IGB3aW5kb3cuYXBwYCBpcyBkZWZpbmVkIGVhcmx5LCBhbmQgYSBzbG93IGJvb3QgcmVuZGVycyBhXG4gKiBub24tZW1wdHkgbG9hZGluZyBzaGVsbCBcdTIwMTQgc28gdGhlcmUgaXMgbm8gZmFsc2UtcG9zaXRpdmUgcGF0aCBvbiBhIHZhbGlkIGJvb3QuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSBzYW1wbGVkIG9ic2VydmF0aW9uIHBsdXMgd2hldGhlciB0aGUgZ3JhY2UgaGFzIGVsYXBzZWQuXG4gKiBAcmV0dXJucyBgJ2RlYWQnYCB3aGVuIHRoZSByZW5kZXJlciBpcyB0ZXJtaW5hbGx5IGRlYWQsIG90aGVyd2lzZSBgJ3BlbmRpbmcnYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrUmVuZGVyZXJCb290U3RhdGUocGFyYW1zOiBDaGVja1JlbmRlcmVyQm9vdFN0YXRlUGFyYW1zKTogUmVuZGVyZXJCb290VmVyZGljdCB7XG4gIGNvbnN0IHsgYm9keUNoaWxkRWxlbWVudENvdW50LCBoYXNHcmFjZUVsYXBzZWQsIGhhc1dpbmRvd0FwcCwgaXNEb2N1bWVudENvbXBsZXRlIH0gPSBwYXJhbXM7XG5cbiAgaWYgKGhhc1dpbmRvd0FwcCkge1xuICAgIHJldHVybiAncGVuZGluZyc7XG4gIH1cblxuICBpZiAoIWhhc0dyYWNlRWxhcHNlZCkge1xuICAgIHJldHVybiAncGVuZGluZyc7XG4gIH1cblxuICBpZiAoaXNEb2N1bWVudENvbXBsZXRlICYmIGJvZHlDaGlsZEVsZW1lbnRDb3VudCA9PT0gMCkge1xuICAgIHJldHVybiAnZGVhZCc7XG4gIH1cblxuICByZXR1cm4gJ3BlbmRpbmcnO1xufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBkZWFkLWJvb3QgZmFzdC1mYWlsIGdyYWNlIHdpbmRvdywgYXBwbHlpbmcgdGhlIGRlZmF1bHQgd2hlbiB0aGVcbiAqIG9wdGlvbiBpcyBvbWl0dGVkLlxuICpcbiAqIFRoaXMgYm91bmRzIGhvdyBsb25nIHRoZSBvd25lZC12YXVsdCByZWFkaW5lc3MgcG9sbCB3YWl0cyBcdTIwMTQgYWZ0ZXIgdGhlIHJlbmRlcmVyXG4gKiBmaXJzdCByZWFjaGVzIGBkb2N1bWVudC5yZWFkeVN0YXRlYCBgJ2NvbXBsZXRlJ2AgXHUyMDE0IGJlZm9yZSBjb25jbHVkaW5nIHRoZSBib290XG4gKiBpcyBkZWFkIChzZWUge0BsaW5rIGNoZWNrUmVuZGVyZXJCb290U3RhdGV9KS4gQSB2YWx1ZSBvZiBgMGAgZGlzYWJsZXMgZmFzdC1mYWlsXG4gKiBlbnRpcmVseSwgcmVzdG9yaW5nIHRoZSBwbGFpbiB3YWl0LW91dC10aGUtcmVhZGluZXNzLXRpbWVvdXQgYmVoYXZpb3IuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgZGVza3RvcCBDRFAgdHJhbnNwb3J0IG9wdGlvbnMgKG9yIHRoZSByZWxldmFudCBzbGljZSkuXG4gKiBAcmV0dXJucyBUaGUgZ3JhY2Ugd2luZG93IGluIG1pbGxpc2Vjb25kcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEZWFkQm9vdEdyYWNlSW5NaWxsaXNlY29uZHMoXG4gIG9wdGlvbnM/OiBQaWNrPE9ic2lkaWFuQ2RwVHJhbnNwb3J0T3B0aW9ucywgJ2RlYWRCb290R3JhY2VJbk1pbGxpc2Vjb25kcyc+XG4pOiBudW1iZXIge1xuICByZXR1cm4gb3B0aW9ucz8uZGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzID8/IERFRkFVTFRfREVBRF9CT09UX0dSQUNFX0lOX01JTExJU0VDT05EUztcbn1cbiJdLAogICJtYXBwaW5ncyI6ICJBQXlCTyxNQUFNLDBDQUEwQztBQW9EaEQsU0FBUyx1QkFBdUIsUUFBMkQ7QUFDaEcsUUFBTSxFQUFFLHVCQUF1QixpQkFBaUIsY0FBYyxtQkFBbUIsSUFBSTtBQUVyRixNQUFJLGNBQWM7QUFDaEIsV0FBTztBQUFBLEVBQ1Q7QUFFQSxNQUFJLENBQUMsaUJBQWlCO0FBQ3BCLFdBQU87QUFBQSxFQUNUO0FBRUEsTUFBSSxzQkFBc0IsMEJBQTBCLEdBQUc7QUFDckQsV0FBTztBQUFBLEVBQ1Q7QUFFQSxTQUFPO0FBQ1Q7QUFjTyxTQUFTLG1DQUNkLFNBQ1E7QUFDUixTQUFPLFNBQVMsK0JBQStCO0FBQ2pEOyIsCiAgIm5hbWVzIjogW10KfQo=
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file
3
+ *
4
+ * The distinct error thrown when the owned Obsidian renderer terminally fails to
5
+ * initialize — the asar could not run on the launched Electron shell (the
6
+ * installer/Electron version is too old for the Obsidian app version). It is
7
+ * exported so callers of `connectToCdp` / the transport can `instanceof`-match
8
+ * this specific failure and distinguish it from a generic readiness timeout.
9
+ */
10
+ /**
11
+ * Thrown when the owned Obsidian renderer loads but never bootstraps the app —
12
+ * an empty `<body>` with no `window.app` after the boot grace window (see
13
+ * `checkRendererBootState`). The usual cause is an installer/Electron shell too
14
+ * old for the pinned Obsidian app version.
15
+ */
16
+ export declare class RendererFailedToInitializeError extends Error {
17
+ /**
18
+ * Creates the error for a specific vault.
19
+ *
20
+ * @param vaultPath - The vault whose owned renderer failed to initialize.
21
+ */
22
+ constructor(vaultPath: string);
23
+ }
@@ -0,0 +1,17 @@
1
+ class RendererFailedToInitializeError extends Error {
2
+ /**
3
+ * Creates the error for a specific vault.
4
+ *
5
+ * @param vaultPath - The vault whose owned renderer failed to initialize.
6
+ */
7
+ constructor(vaultPath) {
8
+ super(
9
+ `The Obsidian renderer for vault ${vaultPath} did not initialize on this Electron shell. The installer/Electron version is likely too old for this Obsidian app version. Pin a newer obsidianInstallerVersion, or align obsidianVersion with the installed shell.`
10
+ );
11
+ this.name = "RendererFailedToInitializeError";
12
+ }
13
+ }
14
+ export {
15
+ RendererFailedToInitializeError
16
+ };
17
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3JlbmRlcmVyLWZhaWxlZC10by1pbml0aWFsaXplLWVycm9yLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogVGhlIGRpc3RpbmN0IGVycm9yIHRocm93biB3aGVuIHRoZSBvd25lZCBPYnNpZGlhbiByZW5kZXJlciB0ZXJtaW5hbGx5IGZhaWxzIHRvXG4gKiBpbml0aWFsaXplIFx1MjAxNCB0aGUgYXNhciBjb3VsZCBub3QgcnVuIG9uIHRoZSBsYXVuY2hlZCBFbGVjdHJvbiBzaGVsbCAodGhlXG4gKiBpbnN0YWxsZXIvRWxlY3Ryb24gdmVyc2lvbiBpcyB0b28gb2xkIGZvciB0aGUgT2JzaWRpYW4gYXBwIHZlcnNpb24pLiBJdCBpc1xuICogZXhwb3J0ZWQgc28gY2FsbGVycyBvZiBgY29ubmVjdFRvQ2RwYCAvIHRoZSB0cmFuc3BvcnQgY2FuIGBpbnN0YW5jZW9mYC1tYXRjaFxuICogdGhpcyBzcGVjaWZpYyBmYWlsdXJlIGFuZCBkaXN0aW5ndWlzaCBpdCBmcm9tIGEgZ2VuZXJpYyByZWFkaW5lc3MgdGltZW91dC5cbiAqL1xuXG4vKipcbiAqIFRocm93biB3aGVuIHRoZSBvd25lZCBPYnNpZGlhbiByZW5kZXJlciBsb2FkcyBidXQgbmV2ZXIgYm9vdHN0cmFwcyB0aGUgYXBwIFx1MjAxNFxuICogYW4gZW1wdHkgYDxib2R5PmAgd2l0aCBubyBgd2luZG93LmFwcGAgYWZ0ZXIgdGhlIGJvb3QgZ3JhY2Ugd2luZG93IChzZWVcbiAqIGBjaGVja1JlbmRlcmVyQm9vdFN0YXRlYCkuIFRoZSB1c3VhbCBjYXVzZSBpcyBhbiBpbnN0YWxsZXIvRWxlY3Ryb24gc2hlbGwgdG9vXG4gKiBvbGQgZm9yIHRoZSBwaW5uZWQgT2JzaWRpYW4gYXBwIHZlcnNpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBSZW5kZXJlckZhaWxlZFRvSW5pdGlhbGl6ZUVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgZXJyb3IgZm9yIGEgc3BlY2lmaWMgdmF1bHQuXG4gICAqXG4gICAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgdmF1bHQgd2hvc2Ugb3duZWQgcmVuZGVyZXIgZmFpbGVkIHRvIGluaXRpYWxpemUuXG4gICAqL1xuICBwdWJsaWMgY29uc3RydWN0b3IodmF1bHRQYXRoOiBzdHJpbmcpIHtcbiAgICBzdXBlcihcbiAgICAgIGBUaGUgT2JzaWRpYW4gcmVuZGVyZXIgZm9yIHZhdWx0ICR7dmF1bHRQYXRofSBkaWQgbm90IGluaXRpYWxpemUgb24gdGhpcyBFbGVjdHJvbiBzaGVsbC4gYFxuICAgICAgICArICdUaGUgaW5zdGFsbGVyL0VsZWN0cm9uIHZlcnNpb24gaXMgbGlrZWx5IHRvbyBvbGQgZm9yIHRoaXMgT2JzaWRpYW4gYXBwIHZlcnNpb24uICdcbiAgICAgICAgKyAnUGluIGEgbmV3ZXIgb2JzaWRpYW5JbnN0YWxsZXJWZXJzaW9uLCBvciBhbGlnbiBvYnNpZGlhblZlcnNpb24gd2l0aCB0aGUgaW5zdGFsbGVkIHNoZWxsLidcbiAgICApO1xuICAgIHRoaXMubmFtZSA9ICdSZW5kZXJlckZhaWxlZFRvSW5pdGlhbGl6ZUVycm9yJztcbiAgfVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIkFBZ0JPLE1BQU0sd0NBQXdDLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFNbEQsWUFBWSxXQUFtQjtBQUNwQztBQUFBLE1BQ0UsbUNBQW1DLFNBQVM7QUFBQSxJQUc5QztBQUNBLFNBQUssT0FBTztBQUFBLEVBQ2Q7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K
@@ -16,6 +16,7 @@
16
16
  *
17
17
  * Requirements: Node.js 22+ (uses built-in `WebSocket` and `fetch` globals).
18
18
  */
19
+ import type { InstallerCompatibility } from './installer-compatibility.mjs';
19
20
  import type { ObsidianTransport, TransportEvalOptions } from './transport.mjs';
20
21
  /**
21
22
  * Configuration for the CDP transport.
@@ -36,6 +37,13 @@ export interface DesktopCdpTransportConfig {
36
37
  * Defaults to `30000`.
37
38
  */
38
39
  commandTimeoutInMilliseconds?: number;
40
+ /**
41
+ * Grace window in milliseconds for fast-failing a dead boot of the owned
42
+ * instance (empty `<body>` with no `window.app` after the renderer reached
43
+ * `document.readyState` `'complete'`). Defaults to
44
+ * {@link DEFAULT_DEAD_BOOT_GRACE_IN_MILLISECONDS}. `0` disables fast-fail.
45
+ */
46
+ deadBootGraceInMilliseconds?: number;
39
47
  /**
40
48
  * When attaching (i.e. {@link cdpPort} is set), marks the target as a
41
49
  * **harness-owned, already-prepared** instance. Suppresses the user-scope
@@ -49,7 +57,7 @@ export interface DesktopCdpTransportConfig {
49
57
  * its window is moved off-screen after launch. Only meaningful in owned mode;
50
58
  * attach mode never touches the (user's) window.
51
59
  *
52
- * @default `false`
60
+ * @default `true`
53
61
  */
54
62
  isObsidianAppVisible?: boolean;
55
63
  /**
@@ -57,6 +65,15 @@ export interface DesktopCdpTransportConfig {
57
65
  * instead of attaching to a running one. This is the default desktop mode.
58
66
  */
59
67
  ownedInstance?: OwnedInstanceConfig;
68
+ /**
69
+ * Whether to launch the owned instance with Chromium's sandbox disabled
70
+ * (`--no-sandbox`). Needed to boot on Linux without a correctly-configured
71
+ * setuid `chrome-sandbox` helper (e.g. an extracted portable shell, or CI as a
72
+ * non-root user); harmless on Windows/macOS. Only meaningful in owned mode.
73
+ *
74
+ * @default `false`
75
+ */
76
+ shouldDisableSandbox?: boolean;
60
77
  }
61
78
  /**
62
79
  * An asar to provision into a harness-owned instance's user-data dir before launch.
@@ -76,6 +93,12 @@ export interface OwnedInstanceAsar {
76
93
  export interface OwnedInstanceConfig {
77
94
  /** Optional asar to provision into {@link userDataDir} before launch. */
78
95
  readonly asar?: OwnedInstanceAsar | undefined;
96
+ /**
97
+ * The resolved installer↔app compatibility verdict, when it could be determined
98
+ * (an asar-swap onto a known shell version). Surfaced by
99
+ * {@link DesktopCdpTransport.getCompatibility}.
100
+ */
101
+ readonly compatibility?: InstallerCompatibility | undefined;
79
102
  /** Absolute path to the Obsidian shell executable to launch. */
80
103
  readonly exePath: string;
81
104
  /**
@@ -109,11 +132,13 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
109
132
  private cdpPort;
110
133
  private cdpUrl;
111
134
  private readonly commandTimeoutInMilliseconds;
135
+ private readonly deadBootGraceInMilliseconds;
112
136
  private readonly isHarnessOwnedInstance;
113
137
  private readonly isObsidianAppVisible;
114
138
  private messageId;
115
139
  private readonly ownedConfig;
116
140
  private ownedInstance;
141
+ private readonly shouldDisableSandbox;
117
142
  private ws;
118
143
  /**
119
144
  * Creates a new CDP transport.
@@ -145,6 +170,15 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
145
170
  * @returns The normalized result string.
146
171
  */
147
172
  evaluate(expression: string, options: TransportEvalOptions): Promise<string>;
173
+ /**
174
+ * Returns the resolved installer↔app compatibility verdict for this owned
175
+ * instance, so callers can assert on it. Returns `undefined` when this is not
176
+ * an owned instance, or the verdict could not be determined (e.g. an
177
+ * undetectable shell version, or the app version is absent from the table).
178
+ *
179
+ * @returns The compatibility verdict, or `undefined`.
180
+ */
181
+ getCompatibility(): InstallerCompatibility | undefined;
148
182
  /**
149
183
  * Returns the CDP endpoint of the owned, launched instance so the global setup
150
184
  * can hand it to test workers (which then **attach** to it instead of
@@ -268,6 +302,17 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
268
302
  * @param vaultPath - The absolute path to the vault folder.
269
303
  */
270
304
  private openVaultInRunningInstance;
305
+ /**
306
+ * Samples the vault renderer's bootstrap state — whether the document is
307
+ * `complete`, whether `window.app` exists, and the `<body>` child count — from
308
+ * the first page target, for dead-boot detection. This works even when the app
309
+ * never bootstrapped (the renderer page target still exists), which is exactly
310
+ * the state it must observe.
311
+ *
312
+ * @returns The sampled observation, or `undefined` when no target is reachable
313
+ * or the probe failed (so the caller keeps polling rather than fast-failing).
314
+ */
315
+ private probeRendererBootState;
271
316
  /**
272
317
  * Probes a target to discover which vault path it has open.
273
318
  *
@@ -321,6 +366,15 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
321
366
  * Polls the owned instance until the vault target exists, layout is ready, and
322
367
  * the trust dialog (if any) has been dismissed.
323
368
  *
369
+ * Between readiness attempts it also checks for a **dead boot** — the renderer
370
+ * loaded (`document.readyState` `'complete'`) but the app never bootstrapped
371
+ * (empty `<body>`, no `window.app`), the terminal state when the asar cannot
372
+ * run on the launched Electron shell. Once that state has held for the
373
+ * configured grace window it throws a {@link RendererFailedToInitializeError}
374
+ * immediately instead of waiting out the full readiness timeout. A grace of
375
+ * `0` disables the fast-fail. The grace clock starts when the renderer first
376
+ * reports `complete`, so a slow load before then is never counted against it.
377
+ *
324
378
  * @param vaultPath - The absolute path to the vault folder.
325
379
  */
326
380
  private waitForOwnedVaultReady;