@jbrowse/plugin-blat 5.0.0-beta.1 → 5.0.0-beta.11

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/esm/BlatDialog.js CHANGED
@@ -7,7 +7,7 @@ import MonospaceTextField from './MonospaceTextField.js';
7
7
  import UcscQueryActions from './UcscQueryActions.js';
8
8
  import UcscQueryFields from './UcscQueryFields.js';
9
9
  import UcscQueryStatus from './UcscQueryStatus.js';
10
- import { DEFAULT_BLAT_URL, UCSC_BLAT_URL, MAXIMUM_BLAT_LENGTH, MAXIMUM_BLAT_QUERIES, MINIMUM_BLAT_LENGTH, buildBlatBody, fastaRecordCount, parseBlatResponse, pslToFeatures, queryLabel, stripFasta, } from './blatQuery.js';
10
+ import { DEFAULT_BLAT_URL, UCSC_BLAT_URL, MINIMUM_BLAT_LENGTH, blatQueryProblem, blatResidueCount, buildBlatBody, parseBlatResponse, parseFastaRecords, pslToFeatures, queryLabel, } from './blatQuery.js';
11
11
  import { parseQuerySequences, pslToSam } from './pslToSam.js';
12
12
  import { canRenderAlignments } from './ucscShared.js';
13
13
  import { runUcscFetch, useUcscQuery } from './useUcscQuery.js';
@@ -20,20 +20,14 @@ const BlatDialog = observer(function BlatDialog({ session, handleClose, }) {
20
20
  });
21
21
  const { db, urlBase, fallbackUrl, apiKey } = query;
22
22
  const [seq, setSeq] = useState('');
23
- const residues = stripFasta(seq);
24
- const queryCount = fastaRecordCount(seq);
25
- const tooShort = residues.length < MINIMUM_BLAT_LENGTH;
26
- const tooLong = residues.length > MAXIMUM_BLAT_LENGTH;
27
- const tooMany = queryCount > MAXIMUM_BLAT_QUERIES;
28
- const seqError = tooLong
29
- ? `Sequence is ${residues.length.toLocaleString()} bp; UCSC BLAT is limited to ${MAXIMUM_BLAT_LENGTH.toLocaleString()} bp`
30
- : tooMany
31
- ? `${queryCount} sequences; UCSC BLAT is limited to ${MAXIMUM_BLAT_QUERIES} per query`
32
- : tooShort && residues
33
- ? `Sequence must be at least ${MINIMUM_BLAT_LENGTH} bp`
34
- : '';
23
+ const records = parseFastaRecords(seq);
24
+ const queryCount = records.length;
25
+ const seqError = blatQueryProblem(records);
26
+ // an empty box disables submit without turning the field red, so the minimum
27
+ // is checked here rather than reported above
28
+ const submittable = !seqError && blatResidueCount(records) >= MINIMUM_BLAT_LENGTH;
35
29
  async function handleSubmit() {
36
- const label = queryLabel(seq);
30
+ const label = queryLabel(records);
37
31
  await query.runQuery({
38
32
  // PSL states each hit as aligned blocks in query and target coordinates,
39
33
  // which is a CIGAR alignment: converting to SAM and showing it in an
@@ -86,7 +80,7 @@ const BlatDialog = observer(function BlatDialog({ session, handleClose, }) {
86
80
  }, children: [_jsxs(DialogContent, { style: { display: 'flex', flexDirection: 'column', gap: 12 }, children: [_jsx(MonospaceTextField, { label: "Sequence", value: seq, onChange: event => {
87
81
  setSeq(event.target.value);
88
82
  }, multiline: true, minRows: 6, maxRows: 14, autoFocus: true, placeholder: "Paste a DNA sequence or FASTA to locate it in the genome", error: !!seqError, helperText: seqError ||
89
- 'DNA, or FASTA with up to 25 records, 25 kb total. Hits are added as a track, and listed best-first in a panel where each one is a link.' }), _jsx(UcscQueryFields, { session: session, query: query, urlLabel: "BLAT server URL" }), _jsx(UcscQueryStatus, { query: query })] }), _jsx(UcscQueryActions, { query: query, submitDisabled: tooShort || tooLong || tooMany || !db, onSubmit: () => void handleSubmit(), onCancel: () => {
83
+ 'DNA, or FASTA with up to 25 records, 25 kb each and 50 kb in total. Hits are added as a track, and listed best-first in a panel where each one is a link.' }), _jsx(UcscQueryFields, { session: session, query: query, urlLabel: "BLAT server URL" }), _jsx(UcscQueryStatus, { query: query })] }), _jsx(UcscQueryActions, { query: query, submitDisabled: !submittable || !db, onSubmit: () => void handleSubmit(), onCancel: () => {
90
84
  handleClose();
91
85
  } })] }));
92
86
  });
@@ -1 +1 @@
1
- export declare const configSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
1
+ export declare const configSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
@@ -1,13 +1,14 @@
1
- import { lazy } from 'react';
2
1
  import WidgetType from '@jbrowse/core/pluggableElementTypes/WidgetType';
2
+ import { lazyWithPreload } from '@jbrowse/core/util/lazyWithPreload';
3
3
  import { configSchema } from './configSchema.js';
4
4
  import { stateModelFactory } from './stateModel.js';
5
5
  export default function UcscResultsWidgetF(pluginManager) {
6
6
  pluginManager.addWidgetType(() => new WidgetType({
7
7
  name: 'UcscResultsWidget',
8
+ discardOnClose: true,
8
9
  heading: 'Search results',
9
10
  configSchema,
10
11
  stateModel: stateModelFactory(),
11
- ReactComponent: lazy(() => import('./UcscResultsWidget.js')),
12
+ ReactComponent: lazyWithPreload(() => import('./UcscResultsWidget.js')),
12
13
  }));
13
14
  }
@@ -36,7 +36,7 @@ export declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").
36
36
  * product, which is a band on a gel — the word a bench scientist reasons in,
37
37
  * and "2 hits" understates what two of them mean for a PCR run
38
38
  */
39
- resultNoun: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
39
+ resultNoun: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<"hit" | "product">, [undefined]>;
40
40
  }, {}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
41
41
  export type UcscResultsWidgetStateModel = ReturnType<typeof stateModelFactory>;
42
42
  export type UcscResultsWidgetModel = Instance<UcscResultsWidgetStateModel>;
@@ -37,11 +37,36 @@ export interface PslRow {
37
37
  export declare function parsePslRows(data: BlatJsonResponse): PslRow[];
38
38
  export declare function pslToFeatures(rows: PslRow[]): SimpleFeatureSerialized[];
39
39
  export declare const MINIMUM_BLAT_LENGTH = 20;
40
- export declare const MAXIMUM_BLAT_LENGTH = 25000;
40
+ export declare const MAXIMUM_BLAT_SEQUENCE_LENGTH = 25000;
41
+ export declare const MAXIMUM_BLAT_TOTAL_LENGTH = 50000;
41
42
  export declare const MAXIMUM_BLAT_QUERIES = 25;
42
- export declare function stripFasta(seq: string): string;
43
- export declare function fastaRecordCount(seq: string): number;
44
- export declare function queryLabel(seq: string): string;
43
+ /**
44
+ * One submitted FASTA record. `name` is the header's first token and is absent
45
+ * for a bare sequence, which hgBlat labels `YourSeq`.
46
+ *
47
+ * `residues` keeps letters only, which is what kent's FASTA reader counts and
48
+ * therefore what both the limits and `qSize` are stated in: a sequence pasted
49
+ * with line numbers or alignment-gap dashes is fewer bases to BLAT than it has
50
+ * characters.
51
+ */
52
+ export interface FastaRecord {
53
+ name?: string;
54
+ residues: string;
55
+ }
56
+ /**
57
+ * The submitted text split the way hgBlat splits it: each record is placed
58
+ * separately and its hits are labelled with its name. The length limits, the
59
+ * track label and the name-to-bases map the SAM conversion needs all come off
60
+ * this one reader, so none of them can disagree about where a record starts.
61
+ *
62
+ * The text itself still goes to the server verbatim — stripping the headers here
63
+ * would fuse a multi-record paste into one chimeric query and throw away the
64
+ * names that tell the hits apart.
65
+ */
66
+ export declare function parseFastaRecords(text: string): FastaRecord[];
67
+ export declare function blatResidueCount(records: FastaRecord[]): number;
68
+ export declare function blatQueryProblem(records: FastaRecord[]): string;
69
+ export declare function queryLabel(records: FastaRecord[]): string;
45
70
  export declare function buildBlatBody({ db, seq, apiKey, }: {
46
71
  db: string;
47
72
  seq: string;
package/esm/blatQuery.js CHANGED
@@ -113,43 +113,86 @@ function pslRowToFeature(row, featureIndex) {
113
113
  };
114
114
  }
115
115
  export function pslToFeatures(rows) {
116
- return rows.map((row, i) => pslRowToFeature(row, i));
116
+ return rows.map(pslRowToFeature);
117
117
  }
118
118
  export const MINIMUM_BLAT_LENGTH = 20;
119
- // UCSC rejects queries over 25kb server-side; enforce locally for a clear message
120
- export const MAXIMUM_BLAT_LENGTH = 25000;
121
- // hgBlat's per-submission cap on FASTA records
119
+ // hgBlat's own three caps, which its submission page states: 25,000 bases in one
120
+ // DNA sequence, 50,000 across a multi-record submission, 25 records. The
121
+ // per-sequence and combined numbers are separate limits — holding the total to
122
+ // 25,000 refused a three-record FASTA the server would have taken.
123
+ export const MAXIMUM_BLAT_SEQUENCE_LENGTH = 25000;
124
+ export const MAXIMUM_BLAT_TOTAL_LENGTH = 50000;
122
125
  export const MAXIMUM_BLAT_QUERIES = 25;
123
- // residues only, for the length limits. The query itself goes to the server
124
- // verbatim: hgBlat parses FASTA and labels each hit with its record's name, so
125
- // stripping headers here would fuse a multi-record paste into one chimeric
126
- // query and throw away the names that tell the hits apart.
127
- //
128
- // Letters only, which is what kent's FASTA reader counts and therefore what the
129
- // limits are stated in — a sequence pasted with line numbers or alignment-gap
130
- // dashes is fewer bases to BLAT than it has characters. Counting whitespace out
131
- // but digits in measured a 25kb-limited query against a number the server does
132
- // not use. Same rule as parseQuerySequences, which has to agree with `qSize`.
133
- export function stripFasta(seq) {
134
- return seq
135
- .split('\n')
136
- .filter(line => !line.startsWith('>'))
137
- .join('')
138
- .replaceAll(/[^A-Za-z]/g, '');
139
- }
140
- // hgBlat places each FASTA record separately, so records are queries
141
- export function fastaRecordCount(seq) {
142
- const headers = seq.match(/^>/gm);
143
- return headers ? headers.length : 1;
144
- }
145
- // names the result track after what was searched: the first FASTA header, or
126
+ /**
127
+ * The submitted text split the way hgBlat splits it: each record is placed
128
+ * separately and its hits are labelled with its name. The length limits, the
129
+ * track label and the name-to-bases map the SAM conversion needs all come off
130
+ * this one reader, so none of them can disagree about where a record starts.
131
+ *
132
+ * The text itself still goes to the server verbatim — stripping the headers here
133
+ * would fuse a multi-record paste into one chimeric query and throw away the
134
+ * names that tell the hits apart.
135
+ */
136
+ export function parseFastaRecords(text) {
137
+ const records = [];
138
+ let name;
139
+ let residues = [];
140
+ const flush = () => {
141
+ const joined = residues.join('');
142
+ if (joined) {
143
+ records.push({ name, residues: joined });
144
+ }
145
+ };
146
+ for (const line of text.split('\n')) {
147
+ if (line.startsWith('>')) {
148
+ flush();
149
+ name = /^>\s*(\S+)/.exec(line)?.[1];
150
+ residues = [];
151
+ }
152
+ else {
153
+ residues.push(line.replaceAll(/[^A-Za-z]/g, ''));
154
+ }
155
+ }
156
+ flush();
157
+ return records;
158
+ }
159
+ export function blatResidueCount(records) {
160
+ return records.reduce((sum, record) => sum + record.residues.length, 0);
161
+ }
162
+ // Why this query cannot be sent, in the terms hgBlat states its limits in, or
163
+ // '' when it can. Checked here rather than left to the server so an over-long
164
+ // paste says which cap it broke instead of coming back as a kent error page.
165
+ export function blatQueryProblem(records) {
166
+ const total = blatResidueCount(records);
167
+ // reduced rather than spread into Math.max: the record cap is checked below
168
+ // this, so the list reaching here is whatever was pasted
169
+ const longest = records.reduce((max, record) => Math.max(max, record.residues.length), 0);
170
+ const subject = records.length > 1 ? 'Longest sequence' : 'Sequence';
171
+ if (longest > MAXIMUM_BLAT_SEQUENCE_LENGTH) {
172
+ return `${subject} is ${longest.toLocaleString()} bp; UCSC BLAT is limited to ${MAXIMUM_BLAT_SEQUENCE_LENGTH.toLocaleString()} bp per sequence`;
173
+ }
174
+ else if (total > MAXIMUM_BLAT_TOTAL_LENGTH) {
175
+ return `${total.toLocaleString()} bp in total; UCSC BLAT is limited to ${MAXIMUM_BLAT_TOTAL_LENGTH.toLocaleString()} bp per query`;
176
+ }
177
+ else if (records.length > MAXIMUM_BLAT_QUERIES) {
178
+ return `${records.length} sequences; UCSC BLAT is limited to ${MAXIMUM_BLAT_QUERIES} per query`;
179
+ }
180
+ else if (total > 0 && total < MINIMUM_BLAT_LENGTH) {
181
+ return `Sequence must be at least ${MINIMUM_BLAT_LENGTH} bp`;
182
+ }
183
+ else {
184
+ return '';
185
+ }
186
+ }
187
+ // names the result track after what was searched: the first record's header, or
146
188
  // the leading bases of a bare sequence
147
- export function queryLabel(seq) {
148
- const header = /^>\s*(\S+)/m.exec(seq);
149
- const residues = stripFasta(seq);
150
- return header
151
- ? header[1]
152
- : residues.slice(0, 12) + (residues.length > 12 ? '…' : '');
189
+ export function queryLabel(records) {
190
+ const first = records[0];
191
+ if (!first) {
192
+ return '';
193
+ }
194
+ const { name, residues } = first;
195
+ return name ?? residues.slice(0, 12) + (residues.length > 12 ? '…' : '');
153
196
  }
154
197
  export function buildBlatBody({ db, seq, apiKey, }) {
155
198
  const params = new URLSearchParams({
@@ -172,17 +215,21 @@ export function buildBlatBody({ db, seq, apiKey, }) {
172
215
  export class BlatChallengeError extends Error {
173
216
  name = 'BlatChallengeError';
174
217
  }
175
- // Markers on a Cloudflare Turnstile challenge page. Every marker has to be
176
- // specific to the challenge itself: a bare `cf-`, `captcha` or `challenge` also
177
- // matches an ordinary UCSC page, whose standard nav links to
178
- // FAQdownloads.html#CAPTCHA and whose scripts load from challenges.cloudflare.com.
179
- // Those two words made a failed parse of a perfectly good result page report
180
- // itself as a CAPTCHA, sending the user off to solve one that wasn't there.
218
+ // Markers on a Cloudflare Turnstile challenge page. Every marker has to name
219
+ // the widget being MOUNTED, never a page that merely mentions it: a bare `cf-`,
220
+ // `captcha` or `challenge` matches an ordinary UCSC page, whose nav links to
221
+ // FAQdownloads.html#CAPTCHA, and a bare `turnstile` matches one too, because
222
+ // UCSC's Content-Security-Policy whitelists
223
+ // `challenges.cloudflare.com/turnstile/v0/api.js` on every page it serves —
224
+ // including the honest "No matches" that hgPcr answers a primer pair with.
225
+ // Each of those words in turn sent a user off to solve a CAPTCHA that was not
226
+ // there. `turnstile.render(` is the call that puts one on screen, and the
227
+ // challenge page is the only page that makes it.
181
228
  //
182
229
  // Duplicated in `products/aws/blat-proxy/src/routes.ts`, which decides the same thing
183
230
  // about the same pages server-side. The proxy is a standalone package and cannot
184
231
  // import this one, so the copies are deliberate: narrow one and narrow both.
185
- const CHALLENGE_MARKERS = /turnstile|cf[-_]chl/i;
232
+ const CHALLENGE_MARKERS = /turnstile\s*\.\s*render|cf[-_](?:chl|turnstile)/i;
186
233
  export function isChallengePage(text) {
187
234
  return CHALLENGE_MARKERS.test(text);
188
235
  }
package/esm/pslToSam.d.ts CHANGED
@@ -41,14 +41,8 @@ export declare function pslQuerySeq(row: PslRow, querySequences: Map<string, str
41
41
  */
42
42
  export declare function pslToSam(rows: PslRow[], querySequences: Map<string, string>): string;
43
43
  /**
44
- * The submitted query text as name -> residues. hgBlat places each FASTA record
45
- * separately and labels its hits with that record's name, so this is the map
46
- * from a hit back to the bases it was made of.
47
- *
48
- * Keeps only letters, which is what Kent's FASTA reader counts: a pasted
49
- * sequence carrying line numbers, or alignment-gap dashes, is those bases to
50
- * BLAT and so `qSize` excludes them. Stripping only whitespace left our text
51
- * longer than the hit it describes, which is exactly the off-by-N that puts
52
- * every base out of register.
44
+ * The submitted query text as name -> residues, which is the map from a hit back
45
+ * to the bases it was made of. `YourSeq` is what hgBlat calls a record with no
46
+ * header, so that is the name its hits arrive under.
53
47
  */
54
48
  export declare function parseQuerySequences(text: string): Map<string, string>;
package/esm/pslToSam.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { revcom } from '@jbrowse/core/util';
2
+ import { parseFastaRecords } from './blatQuery.js';
2
3
  /**
3
4
  * PSL states a hit as a list of aligned blocks in both query and target
4
5
  * coordinates, which is exactly the information a CIGAR encodes: each block is
@@ -119,35 +120,13 @@ export function pslToSam(rows, querySequences) {
119
120
  ].join('\n');
120
121
  }
121
122
  /**
122
- * The submitted query text as name -> residues. hgBlat places each FASTA record
123
- * separately and labels its hits with that record's name, so this is the map
124
- * from a hit back to the bases it was made of.
125
- *
126
- * Keeps only letters, which is what Kent's FASTA reader counts: a pasted
127
- * sequence carrying line numbers, or alignment-gap dashes, is those bases to
128
- * BLAT and so `qSize` excludes them. Stripping only whitespace left our text
129
- * longer than the hit it describes, which is exactly the off-by-N that puts
130
- * every base out of register.
123
+ * The submitted query text as name -> residues, which is the map from a hit back
124
+ * to the bases it was made of. `YourSeq` is what hgBlat calls a record with no
125
+ * header, so that is the name its hits arrive under.
131
126
  */
132
127
  export function parseQuerySequences(text) {
133
- const sequences = new Map();
134
- let name = 'YourSeq';
135
- let residues = [];
136
- const flush = () => {
137
- if (residues.length) {
138
- sequences.set(name, residues.join(''));
139
- }
140
- };
141
- for (const line of text.split('\n')) {
142
- if (line.startsWith('>')) {
143
- flush();
144
- name = /^>\s*(\S+)/.exec(line)?.[1] ?? 'YourSeq';
145
- residues = [];
146
- }
147
- else {
148
- residues.push(line.replaceAll(/[^A-Za-z]/g, ''));
149
- }
150
- }
151
- flush();
152
- return sequences;
128
+ return new Map(parseFastaRecords(text).map(({ name, residues }) => [
129
+ name ?? 'YourSeq',
130
+ residues,
131
+ ]));
153
132
  }
package/esm/ucscShared.js CHANGED
@@ -1,27 +1,29 @@
1
1
  import { getConf } from '@jbrowse/core/configuration';
2
2
  import { getEnv, isSessionModelWithWidgets, isSessionWithAddSessionTrack, } from '@jbrowse/core/util';
3
+ import { isSameAssemblyName } from '@jbrowse/core/util/tracks';
3
4
  import { assemblyToUcscDb } from './ucscDbMap.js';
4
5
  function isNavigableView(view) {
5
- return ('showTrack' in view &&
6
- typeof view.showTrack === 'function' &&
6
+ return ('launchTrack' in view &&
7
+ typeof view.launchTrack === 'function' &&
7
8
  'navToLocString' in view &&
8
9
  typeof view.navToLocString === 'function');
9
10
  }
10
11
  // jb2hubs stamps the UCSC db on the assembly's sequence.metadata. Its presence
11
12
  // is also the one positive proof that UCSC can search the assembly, so the
12
13
  // dialogs read it directly to decide whether to warn.
14
+ // Annotated rather than inferred: the path runs past `metadata`, a `frozen`
15
+ // slot, so the read is into arbitrary JSON and the path type stops deriving
16
+ // anything at that segment.
13
17
  export function ucscDbStamp(session, name) {
14
18
  const assembly = session.assemblyManager.get(name);
15
- const stamped = assembly
19
+ return assembly
16
20
  ? getConf(assembly, ['sequence', 'metadata', 'blatDb'])
17
21
  : undefined;
18
- return stamped;
19
22
  }
20
23
  // Prefers the stamp, falling back to the static alias map for assemblies whose
21
24
  // configs predate it. Shared by the BLAT and in-silico PCR dialogs.
22
25
  export function resolveUcscDb(session, name) {
23
- const stamped = ucscDbStamp(session, name);
24
- return stamped ? stamped : assemblyToUcscDb(name);
26
+ return ucscDbStamp(session, name) || assemblyToUcscDb(name);
25
27
  }
26
28
  /**
27
29
  * Whether this host can draw a hit as an alignment rather than as plain blocks.
@@ -45,7 +47,8 @@ export function featureLocString(feature) {
45
47
  return `${feature.refName}:${feature.start + 1}-${feature.end}`;
46
48
  }
47
49
  function findNavigableView(session, assembly) {
48
- const view = session.views.find(v => v.type === 'LinearGenomeView' && !!v.assemblyNames?.includes(assembly));
50
+ const view = session.views.find(v => v.type === 'LinearGenomeView' &&
51
+ !!v.assemblyNames?.some(n => isSameAssemblyName(n, assembly, session.assemblyManager)));
49
52
  return view && isNavigableView(view) ? view : undefined;
50
53
  }
51
54
  // Navigates an open view to a hit, growing the window so it lands with flanking
@@ -93,24 +96,24 @@ export async function addResultTrack({ session, assembly, features, trackIdPrefi
93
96
  });
94
97
  const view = findNavigableView(session, assembly);
95
98
  if (view) {
96
- view.showTrack(trackId);
99
+ await view.launchTrack(trackId);
97
100
  }
98
101
  else {
99
102
  session.notify(`Added track "${trackId}" but no open view displays ${assembly}`, 'warning');
100
103
  }
101
104
  // #region showWidget
102
- // addWidget constructs the widget and returns it; showWidget is what puts it
103
- // in the drawer. The third argument is the initial state, so its keys are the
104
- // properties UcscResultsWidget's state model declares. Not every session has
105
- // a drawer — an embedded component may be built without one — so the guard is
106
- // not optional.
105
+ // openWidget constructs the widget and puts it in the drawer, which is
106
+ // addWidget followed by showWidget. The third argument is the initial state,
107
+ // so its keys are the properties UcscResultsWidget's state model declares. Not
108
+ // every session has a drawer — an embedded component may be built without one
109
+ // — so the guard is not optional.
107
110
  if (isSessionModelWithWidgets(session)) {
108
- session.showWidget(session.addWidget('UcscResultsWidget', 'ucscResults', {
111
+ session.openWidget('UcscResultsWidget', 'ucscResults', {
109
112
  features,
110
113
  assembly,
111
114
  trackName,
112
115
  resultNoun,
113
- }));
116
+ });
114
117
  }
115
118
  // #endregion
116
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-blat",
3
- "version": "5.0.0-beta.1",
3
+ "version": "5.0.0-beta.11",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 UCSC BLAT client",
6
6
  "keywords": [
@@ -24,15 +24,16 @@
24
24
  "esbuild": "^0.28.2"
25
25
  },
26
26
  "dependencies": {
27
- "@jbrowse/mobx-state-tree": "^6.5.1",
28
- "@mui/icons-material": "^9.3.1",
29
- "@mui/material": "^9.3.1",
30
- "mobx": "^7.0.3",
27
+ "@jbrowse/mobx-state-tree": "^6.7.0",
28
+ "@mui/icons-material": "^9.4.0",
29
+ "@mui/material": "^9.4.0",
30
+ "mobx": "^7.0.5",
31
31
  "mobx-react": "^10.0.2",
32
- "@jbrowse/core": "^5.0.0-beta.1"
32
+ "@jbrowse/core": "^5.0.0-beta.11"
33
33
  },
34
34
  "peerDependencies": {
35
- "react": ">=19.0.0"
35
+ "react": ">=19.0.0",
36
+ "react-dom": ">=19.0.0"
36
37
  },
37
38
  "publishConfig": {
38
39
  "access": "public"