@jbrowse/capture 5.0.0-beta.10 → 5.0.0-beta.13

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.
@@ -0,0 +1,47 @@
1
+ import type { AnnotationAnchor } from './annotationOverlay.ts';
2
+ import type { JSHandle, Page } from 'puppeteer';
3
+ export interface ViewportRect {
4
+ left: number;
5
+ top: number;
6
+ width: number;
7
+ height: number;
8
+ }
9
+ export interface GraphNodeGeometry extends ViewportRect {
10
+ midX: number;
11
+ midY: number;
12
+ }
13
+ export interface GraphPane {
14
+ scale?: number;
15
+ scaleX?: number;
16
+ scaleY?: number;
17
+ translateX?: number;
18
+ translateY?: number;
19
+ nodePositions?: Record<string, {
20
+ x: number;
21
+ y: number;
22
+ }[]>;
23
+ graph?: {
24
+ nodes: {
25
+ id: string;
26
+ length?: number;
27
+ stable?: {
28
+ rank?: number;
29
+ refName?: string;
30
+ start?: number;
31
+ end?: number;
32
+ };
33
+ }[];
34
+ };
35
+ }
36
+ export declare function locateGraphPaneInPage(viewPath: number[], trackId: string | undefined): {
37
+ pane: GraphPane;
38
+ canvas: Element;
39
+ } | undefined;
40
+ export type LocatedGraphPane = NonNullable<ReturnType<typeof locateGraphPaneInPage>>;
41
+ export declare function nodeGeometryInPage(located: LocatedGraphPane | undefined, nodeId: string): GraphNodeGeometry | undefined;
42
+ export declare function locateGraphPane(page: Page, anchor: Pick<AnnotationAnchor, 'view' | 'trackId'>): Promise<JSHandle<LocatedGraphPane | undefined>>;
43
+ export declare function graphNodePoint(page: Page, anchor: AnnotationAnchor): Promise<{
44
+ x: number;
45
+ y: number;
46
+ } | undefined>;
47
+ export declare function graphNodeRect(page: Page, anchor: AnnotationAnchor, wantBounds: boolean): Promise<ViewportRect | undefined>;
@@ -0,0 +1,120 @@
1
+ // The graph pane an anchor addresses, and the canvas it draws on. The graph is
2
+ // one canvas with no element per node, so the pane is asked where it put one
3
+ // instead, the way a locus anchor asks the LGV. The pane is the addressed view
4
+ // itself when that is a GraphGenomeView, and otherwise a LinearGraphDisplay
5
+ // among the view's tracks, the one `trackId` names or the first: the display
6
+ // itself from plugin 4.0.7, its nested `pane` before that.
7
+ //
8
+ // Puppeteer serializes this into the page, so it closes over nothing.
9
+ export function locateGraphPaneInPage(viewPath, trackId) {
10
+ let view = window.JBrowseSession;
11
+ for (const i of viewPath) {
12
+ view = view?.views?.[i];
13
+ }
14
+ if (!view) {
15
+ return undefined;
16
+ }
17
+ const container = `[data-testid="view-container-${CSS.escape(view.id)}"]`;
18
+ let pane = view;
19
+ let scope = container;
20
+ if (view.tracks) {
21
+ const paneOf = (d) => d.pane ?? (d.type === 'LinearGraphDisplay' ? d : undefined);
22
+ const track = view.tracks.find(t => t.displays?.some(paneOf) &&
23
+ (trackId === undefined || t.configuration?.trackId === trackId));
24
+ const display = track?.displays?.find(paneOf);
25
+ pane = display ? paneOf(display) : undefined;
26
+ const id = track?.configuration?.trackId ?? '';
27
+ scope = `${container} [data-testid="trackRenderingContainer-${CSS.escape(view.id)}-${CSS.escape(id)}"] [data-testid="linear-graph-display"]`;
28
+ }
29
+ const canvas = document.querySelector(`${scope} [data-testid="graph-genome-canvas"]`);
30
+ return pane && canvas ? { pane, canvas } : undefined;
31
+ }
32
+ // Where the located pane drew one GFA segment, in viewport CSS px: its
33
+ // `nodePositions` in graph world units through the transform the renderer
34
+ // draws with. Undefined when the node isn't there, so the caller can fail the
35
+ // spec by name rather than acting on (0,0). Serialized into the page too.
36
+ export function nodeGeometryInPage(located, nodeId) {
37
+ if (!located) {
38
+ return undefined;
39
+ }
40
+ const { pane, canvas } = located;
41
+ // nodePositions is keyed by the node's drawn id, which carries the
42
+ // orientation the cut walked the segment in ('s2037+'), so a spec may name
43
+ // either that or the bare GFA segment id
44
+ const positions = pane.nodePositions;
45
+ const pts = positions?.[nodeId] ??
46
+ positions?.[`${nodeId}+`] ??
47
+ positions?.[`${nodeId}-`];
48
+ if (!pts?.length) {
49
+ return undefined;
50
+ }
51
+ const r = canvas.getBoundingClientRect();
52
+ const scaleX = pane.scaleX ?? pane.scale ?? 1;
53
+ const scaleY = pane.scaleY ?? pane.scale ?? 1;
54
+ const tx = pane.translateX ?? 0;
55
+ const ty = pane.translateY ?? 0;
56
+ const screen = pts.map(p => ({ x: p.x * scaleX + tx, y: p.y * scaleY + ty }));
57
+ const xs = screen.map(p => p.x);
58
+ const ys = screen.map(p => p.y);
59
+ const left = Math.min(...xs);
60
+ const top = Math.min(...ys);
61
+ // Halfway along the drawn line rather than its middle vertex: an anchored
62
+ // node is a two-point line, whose "middle" vertex is its left end, where it
63
+ // meets its neighbour, and the app's hit test there answers the neighbour.
64
+ const legs = screen
65
+ .slice(1)
66
+ .map((p, i) => Math.hypot(p.x - screen[i].x, p.y - screen[i].y));
67
+ let rest = legs.reduce((sum, leg) => sum + leg, 0) / 2;
68
+ let mid = screen[0];
69
+ for (const [i, leg] of legs.entries()) {
70
+ const from = screen[i];
71
+ const to = screen[i + 1];
72
+ if (rest <= leg) {
73
+ const t = leg > 0 ? rest / leg : 0;
74
+ mid = { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
75
+ break;
76
+ }
77
+ rest -= leg;
78
+ mid = to;
79
+ }
80
+ return {
81
+ left: r.left + left,
82
+ top: r.top + top,
83
+ width: Math.max(...xs) - left,
84
+ height: Math.max(...ys) - top,
85
+ midX: r.left + mid.x,
86
+ midY: r.top + mid.y,
87
+ };
88
+ }
89
+ export function locateGraphPane(page, anchor) {
90
+ const path = Array.isArray(anchor.view) ? anchor.view : [anchor.view ?? 0];
91
+ return page.evaluateHandle(locateGraphPaneInPage, path, anchor.trackId);
92
+ }
93
+ async function graphNodeGeometry(page, anchor) {
94
+ const located = await locateGraphPane(page, anchor);
95
+ try {
96
+ return await located.evaluate(nodeGeometryInPage, anchor.graphNode ?? '');
97
+ }
98
+ finally {
99
+ await located.dispose();
100
+ }
101
+ }
102
+ // What a click/hover/ring acts on: a point on the node itself.
103
+ export async function graphNodePoint(page, anchor) {
104
+ const geom = await graphNodeGeometry(page, anchor);
105
+ return geom
106
+ ? { x: geom.midX + (anchor.dx ?? 0), y: geom.midY + (anchor.dy ?? 0) }
107
+ : undefined;
108
+ }
109
+ // What an annotation resolves to: the drawn bounds for a box, a zero-size rect
110
+ // on the node for anything else (so its centre lands on the node, not in the
111
+ // space a bent node encloses).
112
+ export async function graphNodeRect(page, anchor, wantBounds) {
113
+ const geom = await graphNodeGeometry(page, anchor);
114
+ if (!geom) {
115
+ return undefined;
116
+ }
117
+ return wantBounds
118
+ ? { left: geom.left, top: geom.top, width: geom.width, height: geom.height }
119
+ : { left: geom.midX, top: geom.midY, width: 0, height: 0 };
120
+ }
package/esm/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { captureJBrowse, openJBrowse } from './capture.ts';
2
+ export { clearAnnotations, drawAnnotations } from './annotations.ts';
2
3
  export { delay } from './poll.ts';
3
4
  export { waitForFrame, waitForJBrowseReady } from './ready.ts';
4
5
  export { describeDisplays, displayCensusInPage, waitForSession, } from './sessionGate.ts';
@@ -6,6 +7,7 @@ export { jbrowseUrl } from './url.ts';
6
7
  export { assemblyFromSession, encodeSessionSpec, sessionSpecQuery, trackIdsFromSession, } from './session.ts';
7
8
  export { PENDING_DISPLAYS, displayPainted, displaySettled, waitForAppSettled, waitForSelectorAttributed, } from './waits.ts';
8
9
  export { BASE_CHROME_ARGS, findChromeExecutable, isBrowserConsoleNoise, launchBrowser, } from './browser.ts';
10
+ export type { Annotation, AnnotationAnchor } from './annotationOverlay.ts';
9
11
  export type { LaunchOptions } from './browser.ts';
10
12
  export type { CaptureOptions, CaptureResult, OpenOptions, OpenResult, } from './capture.ts';
11
13
  export type { ReadyOptions, ReadyReport } from './ready.ts';
package/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { captureJBrowse, openJBrowse } from './capture.js';
2
+ export { clearAnnotations, drawAnnotations } from './annotations.js';
2
3
  export { delay } from './poll.js';
3
4
  export { waitForFrame, waitForJBrowseReady } from './ready.js';
4
5
  export { describeDisplays, displayCensusInPage, waitForSession, } from './sessionGate.js';
@@ -0,0 +1,4 @@
1
+ import type { Annotation } from './annotationOverlay.ts';
2
+ export declare function readJson(flag: string, value: string): object;
3
+ export declare function readAnnotations(value: string): Annotation[];
4
+ export declare function readSpec(value: string): object;
@@ -0,0 +1,34 @@
1
+ import { readFileSync } from 'node:fs';
2
+ // inline JSON, `-` for stdin, or a path
3
+ function parseJson(flag, value) {
4
+ try {
5
+ const inline = /^\s*[[{]/.test(value);
6
+ return JSON.parse(value === '-'
7
+ ? readFileSync(0, 'utf8')
8
+ : inline
9
+ ? value
10
+ : readFileSync(value, 'utf8'));
11
+ }
12
+ catch (error) {
13
+ throw new Error(`--${flag}: ${error instanceof Error ? error.message : error}`, { cause: error });
14
+ }
15
+ }
16
+ export function readJson(flag, value) {
17
+ const parsed = parseJson(flag, value);
18
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
19
+ throw new Error(`--${flag} must be a JSON object`);
20
+ }
21
+ return parsed;
22
+ }
23
+ export function readAnnotations(value) {
24
+ const parsed = parseJson('annotations', value);
25
+ if (!Array.isArray(parsed)) {
26
+ throw new Error('--annotations must be a JSON array of callouts');
27
+ }
28
+ return parsed;
29
+ }
30
+ // a bare view object is the one-view spec it would be wrapped in
31
+ export function readSpec(value) {
32
+ const spec = readJson('spec', value);
33
+ return 'type' in spec && !('views' in spec) ? { views: [spec] } : spec;
34
+ }
package/esm/poll.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Page } from 'puppeteer';
1
2
  /** The budget each stage of the ready chain gets unless told otherwise. */
2
3
  export declare const DEFAULT_TIMEOUT = 60000;
3
4
  export declare const delay: (ms: number) => Promise<void>;
@@ -12,3 +13,9 @@ export declare function holdTrue(read: () => Promise<boolean>, { holdMs, timeout
12
13
  timeout: number;
13
14
  pollMs: number;
14
15
  }): Promise<boolean>;
16
+ /**
17
+ * Await a page query, answering `fallback` when it failed for a reason a later
18
+ * poll can outlive, such as a navigation destroying the execution context. A
19
+ * closed or crashed page throws, since no poll will recover it.
20
+ */
21
+ export declare function queryWhileOpen<T, F>(page: Page, query: Promise<T>, fallback: F): Promise<T | F>;
package/esm/poll.js CHANGED
@@ -28,3 +28,23 @@ export async function holdTrue(read, { holdMs, timeout, pollMs, }) {
28
28
  }
29
29
  return false;
30
30
  }
31
+ const PAGE_GONE = /crashed|Target closed|Session closed|Connection closed/i;
32
+ /**
33
+ * Await a page query, answering `fallback` when it failed for a reason a later
34
+ * poll can outlive, such as a navigation destroying the execution context. A
35
+ * closed or crashed page throws, since no poll will recover it.
36
+ */
37
+ export async function queryWhileOpen(page, query, fallback) {
38
+ try {
39
+ return await query;
40
+ }
41
+ catch (error) {
42
+ const message = error instanceof Error ? error.message : String(error);
43
+ if (PAGE_GONE.test(message) ||
44
+ page.isClosed() ||
45
+ !page.browser().connected) {
46
+ throw new Error(`the page closed or crashed before it finished rendering (${message})`, { cause: error });
47
+ }
48
+ return fallback;
49
+ }
50
+ }
package/esm/ready.d.ts CHANGED
@@ -19,7 +19,7 @@ export interface ReadyReport {
19
19
  }
20
20
  /**
21
21
  * Wait until the session holds the assembly and tracks asked for, the app has
22
- * held itself ready, and every display has painted.
22
+ * held itself ready, every display has painted, and no error is on screen.
23
23
  */
24
24
  export declare function waitForJBrowseReady(page: Page, options?: ReadyOptions): Promise<ReadyReport>;
25
25
  /**
package/esm/ready.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { DEFAULT_TIMEOUT } from './poll.js';
2
- import { describeDisplays, displayCensusInPage, waitForSession, } from './sessionGate.js';
2
+ import { describeDisplays, displayCensusInPage, errorsShownInPage, waitForSession, } from './sessionGate.js';
3
3
  import { appSettledBlocker } from './waits.js';
4
4
  /**
5
5
  * Wait until the session holds the assembly and tracks asked for, the app has
6
- * held itself ready, and every display has painted.
6
+ * held itself ready, every display has painted, and no error is on screen.
7
7
  */
8
8
  export async function waitForJBrowseReady(page, options = {}) {
9
9
  await waitForSession(page, options);
@@ -33,6 +33,10 @@ export async function waitForFrame(page, { timeout = DEFAULT_TIMEOUT, allowUnset
33
33
  if (canceled.length > 0) {
34
34
  unsettled.push(`display(s) canceled, which lasts until Retry: ${describeDisplays(canceled)}`);
35
35
  }
36
+ const errors = await page.evaluate(errorsShownInPage);
37
+ if (errors.length > 0) {
38
+ unsettled.push(`error(s) on screen: ${errors.join('; ')}`);
39
+ }
36
40
  if (!allowUnsettled && unsettled.length > 0) {
37
41
  const stillLoading = pending.some(d => d.phase === undefined || d.phase === 'loading');
38
42
  const advice = timedOut || stillLoading
@@ -8,7 +8,7 @@ export interface SessionExpectations {
8
8
  */
9
9
  trackIds?: string[];
10
10
  /** The fewest open views that count. Default 1; 0 accepts none. */
11
- views?: number;
11
+ minViews?: number;
12
12
  }
13
13
  export interface SessionCensus {
14
14
  views: number;
@@ -30,7 +30,7 @@ export declare function readSessionInPage(): {
30
30
  * Throws at once with the app's message if it could not load, and on timeout
31
31
  * with what the census held instead.
32
32
  */
33
- export declare function waitForSession(page: Page, { assembly, trackIds, views, timeout, }?: SessionExpectations & {
33
+ export declare function waitForSession(page: Page, { assembly, trackIds, minViews, timeout, }?: SessionExpectations & {
34
34
  timeout?: number;
35
35
  }): Promise<void>;
36
36
  /** One display and the phase it publishes. */
@@ -55,5 +55,11 @@ export declare function displayCensusInPage(): {
55
55
  pending: DisplayState[];
56
56
  tooLarge: DisplayState[];
57
57
  };
58
+ /**
59
+ * The error surfaces no display carries: the toast `notifyError` raises, as a
60
+ * track whose config fails to load does, and the box `ErrorMessage` renders.
61
+ * A track that never opened leaves nothing in {@link displayCensusInPage}.
62
+ */
63
+ export declare function errorsShownInPage(): string[];
58
64
  /** Displays as one clause for a message. */
59
65
  export declare function describeDisplays(displays: DisplayState[]): string;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_TIMEOUT, holdTrue } from './poll.js';
1
+ import { DEFAULT_TIMEOUT, holdTrue, queryWhileOpen } from './poll.js';
2
2
  /**
3
3
  * The load failure the app shows in place of itself, the census
4
4
  * `AppReadyMarker` publishes beside its phase, and any snackbar up — which is
@@ -33,11 +33,11 @@ export function readSessionInPage() {
33
33
  * Throws at once with the app's message if it could not load, and on timeout
34
34
  * with what the census held instead.
35
35
  */
36
- export async function waitForSession(page, { assembly, trackIds = [], views = 1, timeout = DEFAULT_TIMEOUT, } = {}) {
36
+ export async function waitForSession(page, { assembly, trackIds = [], minViews = 1, timeout = DEFAULT_TIMEOUT, } = {}) {
37
37
  let last;
38
38
  const notices = new Set();
39
39
  const reached = await holdTrue(async () => {
40
- const read = await page.evaluate(readSessionInPage).catch(() => undefined);
40
+ const read = await queryWhileOpen(page, page.evaluate(readSessionInPage), undefined);
41
41
  if (read?.failure) {
42
42
  throw new Error(`JBrowse could not load: ${read.failure}`);
43
43
  }
@@ -47,7 +47,7 @@ export async function waitForSession(page, { assembly, trackIds = [], views = 1,
47
47
  const census = read?.census;
48
48
  last = census;
49
49
  return (!!census &&
50
- census.views >= views &&
50
+ census.views >= minViews &&
51
51
  (assembly === undefined || census.assemblies.includes(assembly)) &&
52
52
  trackIds.every(id => census.trackIds.includes(id)));
53
53
  }, { holdMs: 0, timeout, pollMs: 250 });
@@ -67,7 +67,7 @@ export async function waitForSession(page, { assembly, trackIds = [], views = 1,
67
67
  const said = notices.size
68
68
  ? `The app said: ${[...notices].join(' | ')}.`
69
69
  : 'A trackId the config does not define, or an assembly name that does not match the config, looks like this.';
70
- throw new Error(`the session never reached the requested state after ${timeout}ms. Wanted ${wanted || (views > 0 ? 'an open view' : 'a session')}; found ${found}. ${said}`);
70
+ throw new Error(`the session never reached the requested state after ${timeout}ms. Wanted ${wanted || (minViews > 0 ? 'an open view' : 'a session')}; found ${found}. ${said}`);
71
71
  }
72
72
  }
73
73
  /**
@@ -94,6 +94,16 @@ export function displayCensusInPage() {
94
94
  }
95
95
  return { pending, tooLarge };
96
96
  }
97
+ /**
98
+ * The error surfaces no display carries: the toast `notifyError` raises, as a
99
+ * track whose config fails to load does, and the box `ErrorMessage` renders.
100
+ * A track that never opened leaves nothing in {@link displayCensusInPage}.
101
+ */
102
+ export function errorsShownInPage() {
103
+ return [
104
+ ...document.querySelectorAll('[data-testid="snackbar-error"], [data-testid="error-message-box"]'),
105
+ ].map(el => (el.innerText || el.textContent || '').trim().slice(0, 300));
106
+ }
97
107
  /** Displays as one clause for a message. */
98
108
  export function describeDisplays(displays) {
99
109
  return displays
package/esm/url.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const PUBLIC_INSTANCE = "https://jbrowse.org/code/jb2/v5.0.0-beta.10/";
1
+ export declare const PUBLIC_INSTANCE = "https://jbrowse.org/code/jb2/v5.0.0-beta.13/";
2
2
  /**
3
3
  * The instance as the page that loads it sees it: a directory given without
4
4
  * its slash, which the host redirects, resolves relative URLs one level up.
@@ -7,7 +7,7 @@ export declare function instanceUrl(instance?: string): URL;
7
7
  export interface JBrowseUrlOptions {
8
8
  /** A genomes.jbrowse.org assembly: a UCSC db name (`hg38`) or GenArk accession. */
9
9
  hub?: string;
10
- /** A config.json URL, for data that is not on genomes.jbrowse.org. Wins over `hub`. */
10
+ /** A config.json URL, for data that is not on genomes.jbrowse.org. Not combined with `hub`. */
11
11
  config?: string;
12
12
  /** Assembly to open. Defaults to `hub`, whose config names its assembly after it. */
13
13
  assembly?: string;
@@ -32,10 +32,11 @@ export interface JBrowseUrlOptions {
32
32
  instance?: string;
33
33
  }
34
34
  /**
35
- * A spec or a saved session says which assembly, locations and tracks to
36
- * open, so the URL carries one of the three ways of saying so, never two.
35
+ * One source for the config, never a hub and a config URL. A spec or a saved
36
+ * session says which assembly, locations and tracks to open, so the URL carries
37
+ * one of the three ways of saying so, never two.
37
38
  */
38
- export declare function assertSessionStandsAlone({ spec, session, assembly, loc, tracks, }: JBrowseUrlOptions): void;
39
+ export declare function assertCoherentOptions({ hub, config, spec, session, assembly, loc, tracks, }: JBrowseUrlOptions): void;
39
40
  /**
40
41
  * The URL that opens a JBrowse Web instance onto a described view, for a
41
42
  * person to follow without launching a browser here.
package/esm/url.js CHANGED
@@ -9,17 +9,24 @@ export const PUBLIC_INSTANCE = `https://jbrowse.org/code/jb2/v${version}/`;
9
9
  * its slash, which the host redirects, resolves relative URLs one level up.
10
10
  */
11
11
  export function instanceUrl(instance = PUBLIC_INSTANCE) {
12
- const url = new URL(instance);
12
+ const url = URL.parse(instance);
13
+ if (!url || !['http:', 'https:', 'file:'].includes(url.protocol)) {
14
+ throw new Error(`instance "${instance}" is not an http(s) or file URL`);
15
+ }
13
16
  if (!url.pathname.endsWith('/') && !/\.html?$/.test(url.pathname)) {
14
17
  url.pathname += '/';
15
18
  }
16
19
  return url;
17
20
  }
18
21
  /**
19
- * A spec or a saved session says which assembly, locations and tracks to
20
- * open, so the URL carries one of the three ways of saying so, never two.
22
+ * One source for the config, never a hub and a config URL. A spec or a saved
23
+ * session says which assembly, locations and tracks to open, so the URL carries
24
+ * one of the three ways of saying so, never two.
21
25
  */
22
- export function assertSessionStandsAlone({ spec, session, assembly, loc, tracks, }) {
26
+ export function assertCoherentOptions({ hub, config, spec, session, assembly, loc, tracks, }) {
27
+ if (hub && config) {
28
+ throw new Error('pass a hosted hub or a config URL, not both (--hub, --config); name the assembly with --assembly');
29
+ }
23
30
  if (spec && session) {
24
31
  throw new Error('pass a session spec or a saved session, not both');
25
32
  }
@@ -41,7 +48,15 @@ export function assertSessionStandsAlone({ spec, session, assembly, loc, tracks,
41
48
  * takes a locstring only. `session` opens a saved session as exported.
42
49
  */
43
50
  export function jbrowseUrl({ hub, config, assembly, loc, tracks, spec, session, sessionName, instance, }) {
44
- assertSessionStandsAlone({ spec, session, assembly, loc, tracks });
51
+ assertCoherentOptions({
52
+ hub,
53
+ config,
54
+ spec,
55
+ session,
56
+ assembly,
57
+ loc,
58
+ tracks,
59
+ });
45
60
  const params = new URLSearchParams();
46
61
  const set = (key, value) => {
47
62
  if (value) {
package/esm/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.0.0-beta.10";
1
+ export declare const version = "5.0.0-beta.13";
package/esm/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.0.0-beta.10';
1
+ export const version = '5.0.0-beta.13';
package/esm/waits.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_TIMEOUT, holdTrue } from './poll.js';
1
+ import { DEFAULT_TIMEOUT, holdTrue, queryWhileOpen } from './poll.js';
2
2
  import { describeDisplays, displayCensusInPage } from './sessionGate.js';
3
3
  /** The app's own verdict: no view is resolving an assembly, no display is fetching. */
4
4
  export const APP_READY = '[data-app-phase="ready"]';
@@ -64,14 +64,12 @@ const NO_MARKER = 'no [data-app-phase] on the page';
64
64
  * or undefined once the hold passed.
65
65
  */
66
66
  export async function appSettledBlocker(page, { timeout = DEFAULT_TIMEOUT, holdMs = APP_SETTLED_HOLD_MS, pollMs = 250, } = {}) {
67
- const blocker = () => page
68
- .evaluate((ready, blockers, noMarker) => document.querySelector('[data-app-phase]') === null
67
+ const blocker = () => queryWhileOpen(page, page.evaluate((ready, blockers, noMarker) => document.querySelector('[data-app-phase]') === null
69
68
  ? noMarker
70
69
  : (blockers.find(([selector]) => document.querySelector(selector))?.[1] ??
71
70
  (document.querySelector(ready) === null
72
71
  ? 'the marker not reading ready'
73
- : undefined)), APP_READY, SETTLE_BLOCKERS, NO_MARKER)
74
- .catch(() => 'the page could not be queried');
72
+ : undefined)), APP_READY, SETTLE_BLOCKERS, NO_MARKER), 'the page could not be queried');
75
73
  const held = await holdTrue(async () => (await blocker()) === undefined, {
76
74
  holdMs,
77
75
  timeout,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/capture",
3
- "version": "5.0.0-beta.10",
3
+ "version": "5.0.0-beta.13",
4
4
  "description": "Drive a JBrowse 2 instance with Puppeteer and screenshot it once it has actually finished rendering",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -16,7 +16,9 @@
16
16
  "type": "module",
17
17
  "main": "esm/index.js",
18
18
  "exports": {
19
- ".": "./esm/index.js"
19
+ ".": "./esm/index.js",
20
+ "./annotationOverlay": "./esm/annotationOverlay.js",
21
+ "./graphAnchor": "./esm/graphAnchor.js"
20
22
  },
21
23
  "author": "JBrowse Team",
22
24
  "license": "Apache-2.0",
@@ -34,7 +36,7 @@
34
36
  "puppeteer": "^25.12.0"
35
37
  },
36
38
  "devDependencies": {
37
- "@jbrowse/core": "^5.0.0-beta.10"
39
+ "@jbrowse/core": "^5.0.0-beta.13"
38
40
  },
39
41
  "publishConfig": {
40
42
  "access": "public"