@cmdcolin/jbrowse-plugin-hubs 1.0.16 → 1.0.17

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/index.js CHANGED
@@ -1,16 +1,30 @@
1
1
  import Plugin from '@jbrowse/core/Plugin';
2
2
  import { isAbstractMenuManager, isElectron } from '@jbrowse/core/util';
3
- import { getRoot, getSnapshot } from '@jbrowse/mobx-state-tree';
3
+ import { getRoot, getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree';
4
4
  import { getConfigUrls } from './configUrls';
5
5
  import { describeAssemblies } from './describeAssemblies';
6
6
  import { saveAs, toDesktopSnapshot } from './util';
7
7
  import { version } from '../package.json';
8
+ // jbrowse-web's config node, on every host before 6ddcb6f886 (main, after
9
+ // v5.0.0-beta.20), strips each `baseUri` from its own snapshot (a
10
+ // postProcessor meant for the admin "save config" flow), which leaves each
11
+ // relative `uri` bare, and desktop resolves a bare one against the directory
12
+ // the .jbrowse file sits in: ENOENT ~/Downloads/hg38.chromAlias.txt. Its
13
+ // children's snapshots don't pass through that processor, so the config is
14
+ // read from them, baseUris intact, on old hosts and new alike.
15
+ function configSnapshot(jbrowse) {
16
+ const node = jbrowse;
17
+ return Object.fromEntries(Object.keys(getSnapshot(jbrowse)).map(key => {
18
+ const value = node[key];
19
+ return [key, isStateTreeNode(value) ? getSnapshot(value) : value];
20
+ }));
21
+ }
8
22
  // Serializes the current web session as a desktop `.jbrowse` file. genomes
9
23
  // sessions are config-shaped already, so this just folds the live session into
10
24
  // a defaultSession and downloads it; desktop opens it via File > Open session.
11
25
  function downloadDesktopSession(session) {
12
26
  const { jbrowse } = getRoot(session);
13
- const snap = toDesktopSnapshot(getSnapshot(jbrowse), getSnapshot(session));
27
+ const snap = toDesktopSnapshot(configSnapshot(jbrowse), getSnapshot(session));
14
28
  saveAs(new Blob([JSON.stringify(snap, null, 2)], { type: 'application/json' }), 'session.jbrowse');
15
29
  }
16
30
  // Every assembly name this plugin has already taken a run at, whether the probe
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";var JBrowsePluginHubs=(()=>{var I=Object.create;var u=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var g=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),H=(n,e)=>{for(var t in e)u(n,t,{get:e[t],enumerable:!0})},w=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of O(e))!G.call(n,o)&&o!==t&&u(n,o,{get:()=>e[o],enumerable:!(s=U(e,o))||s.enumerable});return n};var m=(n,e,t)=>(t=n!=null?I(P(n)):{},w(e||!n||!n.__esModule?u(t,"default",{value:n,enumerable:!0}):t,n)),B=n=>w(u({},"__esModule",{value:!0}),n);var h=g((Q,k)=>{k.exports=JBrowseExports["@jbrowse/core/Plugin"]});var y=g((Y,j)=>{j.exports=JBrowseExports["@jbrowse/core/util"]});var x=g((Z,A)=>{A.exports=JBrowseExports["mobx-state-tree"]});var V={};H(V,{default:()=>l});var $=m(h()),f=m(y()),a=m(x());function _(n){let[e,t]=n.split("_");if(!t)return;let s=t.match(/.{1,3}/g);if(!s||s.length<3)return;let[o,r,i]=s;return`https://jbrowse.org/hubs/genark/${e}/${o}/${r}/${i}/${n}/config.json`}function c(n){if(!/^[\w.]+$/.test(n))return[];if(n.startsWith("GCA_")||n.startsWith("GCF_")){let t=_(n);return t?[t]:[]}let e=`https://jbrowse.org/ucsc/${n}`;return[`${e}/minimal.json`,`${e}/config.json`]}var v=["ncbiRefSeq","ncbiRefSeqCurated","ncbiGene","refGene","ensGene","augustusGene","xenoRefGene"];function d(n,e){if(Array.isArray(n))return n.map(t=>d(t,e));if(typeof n=="object"&&n!==null){let t=Object.entries(n).map(([s,o])=>[s,d(o,e)]);return Object.fromEntries(typeof n.uri=="string"&&!("baseUri"in n)?[...t,["baseUri",e]]:t)}return n}function J(n,e,t){let s=n.assemblies?.find(i=>i.name===e||i.aliases?.includes(e));if(!s)return;let o=new Map(n.tracks?.map(i=>[i.trackId,i])),r=v.map(i=>o.get(`${s.name}-${i}`)?.adapter).find(i=>i!==void 0);return{assembly:d(s,t),geneAdapter:r&&d(r,t)}}async function F(n){for(let e of c(n)){let t=await fetch(e);if(t.ok){let s=await t.json();return J(s,n,e)}if(t.status!==404)throw new Error(`${e}: HTTP ${t.status}`)}}var b=new Map;function L(n){let e=b.get(n);return e||(e=F(n).catch(t=>{b.delete(n),console.error(t)}),b.set(n,e)),e}async function C(n,e){let t=typeof n=="object"&&n!==null?n:{},s=Array.isArray(e)?e.filter(r=>typeof r=="string"):[],o=await Promise.all(s.filter(r=>!Object.hasOwn(t,r)&&c(r).length>0).map(async r=>[r,await L(r)]));return{...t,...Object.fromEntries(o.filter(([,r])=>r!==void 0))}}function R(n,e){let t=URL.createObjectURL(n),s=document.createElement("a");s.href=t,s.download=e,s.rel="noopener",s.click(),setTimeout(()=>{URL.revokeObjectURL(t)},4e4)}function p(n){return Array.isArray(n)?n:[]}function S(n,e,t){let s=new Map;for(let o of[...n,...e])s.set(o[t],o);return[...s.values()]}function T(n,e){let{sessionTracks:t,sessionAssemblies:s,...o}=e;return{...n,tracks:S(p(n.tracks),p(t),"trackId"),assemblies:S(p(n.assemblies),p(s),"name"),defaultSession:o}}var E="1.0.16";function q(n){let{jbrowse:e}=(0,a.getRoot)(n),t=T((0,a.getSnapshot)(e),(0,a.getSnapshot)(n));R(new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),"session.jbrowse")}var M=new WeakMap;function z(n,e){let t=M.get(n);return t||(t=new Set,M.set(n,t)),t.has(e)?!1:(t.add(e),!0)}async function K(n,e,t){let s=`jb2hub-${e}`;if(!(n.connections.find(o=>o.connectionId===s)||!z(n,e))){for(let o of t)if((await fetch(o,{method:"HEAD"})).ok){let i={type:"JB2TrackHubConnection",uri:o,name:`conn_${e}`,assemblyNames:[e],connectionId:s};n.addConnectionConf(i),n.makeConnection(i,{silent:!0});return}}}var l=class extends $.default{name="HubsViewerPlugin";version=E;install(e){e.addToExtensionPoint("Core-handleUnrecognizedAssembly",(t,s)=>{let o=s.session,r=s.assemblyName,i=r?c(r):[];return o&&r&&i.length>0?K(o,r,i).catch(D=>{console.error(D)}):t}),e.addToExtensionPoint("Core-describeAssemblies",(t,s)=>C(t,s.assemblyNames))}configure(e){if(!f.isElectron&&(0,f.isAbstractMenuManager)(e.rootModel))try{e.rootModel.appendToMenu("Tools",{label:"Download desktop session (.jbrowse)",onClick:t=>{q(t)}})}catch(t){console.error("could not add the desktop-session download item",t)}}};return B(V);})();
1
+ "use strict";var JBrowsePluginHubs=(()=>{var O=Object.create;var u=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var g=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),H=(n,e)=>{for(var t in e)u(n,t,{get:e[t],enumerable:!0})},w=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of U(e))!G.call(n,o)&&o!==t&&u(n,o,{get:()=>e[o],enumerable:!(s=D(e,o))||s.enumerable});return n};var m=(n,e,t)=>(t=n!=null?O(P(n)):{},w(e||!n||!n.__esModule?u(t,"default",{value:n,enumerable:!0}):t,n)),B=n=>w(u({},"__esModule",{value:!0}),n);var h=g((Y,k)=>{k.exports=JBrowseExports["@jbrowse/core/Plugin"]});var y=g((Z,j)=>{j.exports=JBrowseExports["@jbrowse/core/util"]});var x=g((N,A)=>{A.exports=JBrowseExports["mobx-state-tree"]});var X={};H(X,{default:()=>f});var $=m(h()),l=m(y()),c=m(x());function v(n){let[e,t]=n.split("_");if(!t)return;let s=t.match(/.{1,3}/g);if(!s||s.length<3)return;let[o,r,i]=s;return`https://jbrowse.org/hubs/genark/${e}/${o}/${r}/${i}/${n}/config.json`}function a(n){if(!/^[\w.]+$/.test(n))return[];if(n.startsWith("GCA_")||n.startsWith("GCF_")){let t=v(n);return t?[t]:[]}let e=`https://jbrowse.org/ucsc/${n}`;return[`${e}/minimal.json`,`${e}/config.json`]}var _=["ncbiRefSeq","ncbiRefSeqCurated","ncbiGene","refGene","ensGene","augustusGene","xenoRefGene"];function d(n,e){if(Array.isArray(n))return n.map(t=>d(t,e));if(typeof n=="object"&&n!==null){let t=Object.entries(n).map(([s,o])=>[s,d(o,e)]);return Object.fromEntries(typeof n.uri=="string"&&!("baseUri"in n)?[...t,["baseUri",e]]:t)}return n}function J(n,e,t){let s=n.assemblies?.find(i=>i.name===e||i.aliases?.includes(e));if(!s)return;let o=new Map(n.tracks?.map(i=>[i.trackId,i])),r=_.map(i=>o.get(`${s.name}-${i}`)?.adapter).find(i=>i!==void 0);return{assembly:d(s,t),geneAdapter:r&&d(r,t)}}async function F(n){for(let e of a(n)){let t=await fetch(e);if(t.ok){let s=await t.json();return J(s,n,e)}if(t.status!==404)throw new Error(`${e}: HTTP ${t.status}`)}}var b=new Map;function L(n){let e=b.get(n);return e||(e=F(n).catch(t=>{b.delete(n),console.error(t)}),b.set(n,e)),e}async function S(n,e){let t=typeof n=="object"&&n!==null?n:{},s=Array.isArray(e)?e.filter(r=>typeof r=="string"):[],o=await Promise.all(s.filter(r=>!Object.hasOwn(t,r)&&a(r).length>0).map(async r=>[r,await L(r)]));return{...t,...Object.fromEntries(o.filter(([,r])=>r!==void 0))}}function R(n,e){let t=URL.createObjectURL(n),s=document.createElement("a");s.href=t,s.download=e,s.rel="noopener",s.click(),setTimeout(()=>{URL.revokeObjectURL(t)},4e4)}function p(n){return Array.isArray(n)?n:[]}function C(n,e,t){let s=new Map;for(let o of[...n,...e])s.set(o[t],o);return[...s.values()]}function T(n,e){let{sessionTracks:t,sessionAssemblies:s,...o}=e;return{...n,tracks:C(p(n.tracks),p(t),"trackId"),assemblies:C(p(n.assemblies),p(s),"name"),defaultSession:o}}var E="1.0.17";function q(n){let e=n;return Object.fromEntries(Object.keys((0,c.getSnapshot)(n)).map(t=>{let s=e[t];return[t,(0,c.isStateTreeNode)(s)?(0,c.getSnapshot)(s):s]}))}function z(n){let{jbrowse:e}=(0,c.getRoot)(n),t=T(q(e),(0,c.getSnapshot)(n));R(new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),"session.jbrowse")}var M=new WeakMap;function K(n,e){let t=M.get(n);return t||(t=new Set,M.set(n,t)),t.has(e)?!1:(t.add(e),!0)}async function V(n,e,t){let s=`jb2hub-${e}`;if(!(n.connections.find(o=>o.connectionId===s)||!K(n,e))){for(let o of t)if((await fetch(o,{method:"HEAD"})).ok){let i={type:"JB2TrackHubConnection",uri:o,name:`conn_${e}`,assemblyNames:[e],connectionId:s};n.addConnectionConf(i),n.makeConnection(i,{silent:!0});return}}}var f=class extends $.default{name="HubsViewerPlugin";version=E;install(e){e.addToExtensionPoint("Core-handleUnrecognizedAssembly",(t,s)=>{let o=s.session,r=s.assemblyName,i=r?a(r):[];return o&&r&&i.length>0?V(o,r,i).catch(I=>{console.error(I)}):t}),e.addToExtensionPoint("Core-describeAssemblies",(t,s)=>S(t,s.assemblyNames))}configure(e){if(!l.isElectron&&(0,l.isAbstractMenuManager)(e.rootModel))try{e.rootModel.appendToMenu("Tools",{label:"Download desktop session (.jbrowse)",onClick:t=>{z(t)}})}catch(t){console.error("could not add the desktop-session download item",t)}}};return B(X);})();
2
2
  //# sourceMappingURL=jbrowse-plugin-hubs.umd.production.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["global-externals:@jbrowse/core/Plugin", "global-externals:@jbrowse/core/util", "global-externals:@jbrowse/mobx-state-tree", "../src/index.ts", "../src/configUrls.ts", "../src/describeAssemblies.ts", "../src/util.ts", "../package.json"],
4
- "sourcesContent": ["module.exports = JBrowseExports[\"@jbrowse/core/Plugin\"];", "module.exports = JBrowseExports[\"@jbrowse/core/util\"];", "module.exports = JBrowseExports[\"mobx-state-tree\"];", "import Plugin from '@jbrowse/core/Plugin'\nimport { isAbstractMenuManager, isElectron } from '@jbrowse/core/util'\nimport { getRoot, getSnapshot } from '@jbrowse/mobx-state-tree'\n\nimport { getConfigUrls } from './configUrls'\nimport { describeAssemblies } from './describeAssemblies'\nimport { saveAs, toDesktopSnapshot } from './util'\nimport { version } from '../package.json'\n\nimport type PluginManager from '@jbrowse/core/PluginManager'\nimport type { AbstractSessionModel } from '@jbrowse/core/util'\nimport type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree'\n\ninterface Session {\n makeConnection: (conf: unknown, initialSnapshot?: unknown) => void\n addConnectionConf: (conf: unknown) => void\n connections: { connectionId: string }[]\n}\n\n// Serializes the current web session as a desktop `.jbrowse` file. genomes\n// sessions are config-shaped already, so this just folds the live session into\n// a defaultSession and downloads it; desktop opens it via File > Open session.\nfunction downloadDesktopSession(session: AbstractSessionModel) {\n const { jbrowse } = getRoot<{ jbrowse: IAnyStateTreeNode }>(session)\n const snap = toDesktopSnapshot(\n getSnapshot<Record<string, unknown>>(jbrowse),\n getSnapshot<Record<string, unknown>>(session),\n )\n saveAs(\n new Blob([JSON.stringify(snap, null, 2)], { type: 'application/json' }),\n 'session.jbrowse',\n )\n}\n\n// Every assembly name this plugin has already taken a run at, whether the probe\n// is still in flight or came back with nothing. The extension point fires on an\n// unresolved read, and `get` is read from render paths, so a name that resolves\n// to no hosted config is asked about again and again \u2014 GenArk strain hubs\n// (mouseStrains and friends) live under /hubs/genark/<hub>/<strain>/ and are not\n// at the url guessed from the name, and a session can name an assembly this host\n// has never heard of at all. Clearing this once the probe settled (what an\n// earlier `finally` did) meant the next read re-probed, i.e. one HEAD per render\n// forever for exactly the names nothing can supply.\n//\n// A name that DID resolve is also in here, and is separately deduped by\n// connectionId once the connection exists. Nothing is ever removed within a\n// session: a probe answers a question about a url that does not change within a\n// page load.\n//\n// Keyed by session, because the connection a probe created belongs to the\n// session and goes with it. A flat Set would remember a name across\n// `setSession` and leave the new session unable to resolve a genome the old one\n// had. WeakMap so a replaced session is still collectable.\n//\n// jbrowse-core@main reports each unknown name to the extension point once per\n// session, which makes this redundant there \u2014 but this plugin runs against\n// whatever core the host page shipped, down to the v4.0.0 floor, where it is\n// the only thing standing between a mistyped assembly name and an unbounded\n// request stream.\nconst attempted = new WeakMap<Session, Set<string>>()\n\nfunction markAttempted(session: Session, assemblyName: string) {\n let names = attempted.get(session)\n if (!names) {\n names = new Set()\n attempted.set(session, names)\n }\n if (names.has(assemblyName)) {\n return false\n }\n names.add(assemblyName)\n return true\n}\n\n// Connect to the first of `uris` that exists. Connecting to a config that 404s\n// puts a red error snackbar over a session that is otherwise working, so probe\n// first and stay quiet when there's nothing there \u2014 some other handler, or the\n// session itself, may be supplying the assembly.\nasync function connectIfConfigExists(\n session: Session,\n assemblyName: string,\n uris: string[],\n) {\n const connectionId = `jb2hub-${assemblyName}`\n if (\n session.connections.find(f => f.connectionId === connectionId) ||\n !markAttempted(session, assemblyName)\n ) {\n return\n }\n for (const uri of uris) {\n const response = await fetch(uri, { method: 'HEAD' })\n if (response.ok) {\n const conf = {\n type: 'JB2TrackHubConnection',\n uri,\n name: `conn_${assemblyName}`,\n assemblyNames: [assemblyName],\n connectionId,\n }\n session.addConnectionConf(conf)\n // `silent`: no \"Successfully loaded\" snackbar. Nobody asked for this\n // connection \u2014 it exists because a track referenced an assembly the\n // session didn't have \u2014 so announcing it is noise over whatever the\n // user was doing, and it lands on top of any screenshot of a hub\n // genome. The property is newer than every released core (it landed\n // after v4.3.0) and this plugin runs against whatever core the host\n // page shipped, down to the v4.0.0 floor, but passing it is safe\n // regardless: MST drops an undeclared key off a model snapshot rather\n // than rejecting it (verified against the fork \u2014 the instance is\n // created, the key is neither readable on it nor in its snapshot), so\n // an older core makes the same connection it always did and keeps its\n // toast.\n session.makeConnection(conf, { silent: true })\n return\n }\n }\n}\n\nexport default class HubsViewerPlugin extends Plugin {\n name = 'HubsViewerPlugin'\n version = version\n\n install(pluginManager: PluginManager) {\n pluginManager.addToExtensionPoint(\n 'Core-handleUnrecognizedAssembly',\n (defaultResult, args) => {\n const session = args.session as Session | undefined\n const assemblyName = args.assemblyName as string | undefined\n const uris = assemblyName ? getConfigUrls(assemblyName) : []\n if (session && assemblyName && uris.length > 0) {\n // The probe and the connection it may create land after this returns,\n // which is fine because assemblyManager re-reads reactively once the\n // assembly shows up.\n //\n // Returning the promise rather than the accumulator: a core that\n // knows to look (jbrowse-core > 4.3.0) awaits it in waitForAssembly,\n // which is what lets that wait end on an event instead of a 10s\n // timeout. Nothing observable happens between being asked and the\n // HEAD coming back, so a core with only the session to watch has to\n // guess, and 10s is both too long to fail in and too short for a cold\n // CDN. Older cores fold the return value into an accumulator they\n // then discard, so this is inert there.\n //\n // Nothing else registers on this point (checked across the plugin\n // ecosystem), so replacing the accumulator costs no other plugin its\n // result; if that changes, a handler registered after this one still\n // receives and can pass on whatever it is given.\n return connectIfConfigExists(session, assemblyName, uris).catch(\n (e: unknown) => {\n console.error(e)\n },\n )\n }\n // Pass the accumulator through: this extension point chains handlers, so\n // returning undefined would clobber another plugin's result.\n return defaultResult\n },\n )\n // A multi-way synteny lane whose genome the session lacks asks here for\n // its assembly config and gene track. Cores older than the point never\n // fire it, so this is inert on them\n pluginManager.addToExtensionPoint(\n 'Core-describeAssemblies',\n (described: unknown, args) =>\n describeAssemblies(described, args.assemblyNames),\n )\n }\n\n configure(pluginManager: PluginManager) {\n // jbrowse-web only. In desktop you'd just save the session, and an exported\n // .jbrowse file carries this plugin in its plugins list, so an older desktop\n // would otherwise load and run this menu code when opening that file.\n if (!isElectron && isAbstractMenuManager(pluginManager.rootModel)) {\n // 'Tools', not 'File'. Every released core from v4.0.0 to latest defines\n // the File menu as a thunk and appends with `menu.menuItems.push()`, which\n // throws on a function; the throw escapes configure() and renders the app\n // as an error page rather than costing just this menu item. Because the\n // plugin store serves `latest/` no-cache, that took out every\n // jbrowse.org/ucsc launch on hg38/hg19/mm39/hs1 the moment 1.0.9 shipped.\n // core@main resolves item contributions lazily and accepts either form,\n // but this plugin has to keep working on the releases already in the wild.\n //\n // Belt and braces on the same reasoning: a cosmetic menu item should never\n // be able to cost a user their whole session.\n try {\n pluginManager.rootModel.appendToMenu('Tools', {\n label: 'Download desktop session (.jbrowse)',\n onClick: (session: AbstractSessionModel) => {\n downloadDesktopSession(session)\n },\n })\n } catch (e) {\n console.error('could not add the desktop-session download item', e)\n }\n }\n }\n}\n", "function getGenArkConfigUrl(accession: string) {\n const [base, rest] = accession.split('_')\n if (!rest) {\n return undefined\n }\n const match = rest.match(/.{1,3}/g)\n if (!match || match.length < 3) {\n return undefined\n }\n const [b1, b2, b3] = match\n return `https://jbrowse.org/hubs/genark/${base}/${b1}/${b2}/${b3}/${accession}/config.json`\n}\n\n// Candidate urls for an assembly name, most preferred first. The connection\n// probe and the describe lookup each take the first that exists, so a name with\n// no hosted config anywhere is still answered by staying quiet.\n//\n// A UCSC db gets `minimal.json` ahead of `config.json`. Both carry the same\n// `assemblies` block (minimal.json is a filtered copy of config.json, tracks\n// dropped to NCBI RefSeq / GENCODE / RepeatMasker / gaps), and the assembly is\n// the whole reason this connection exists \u2014 the tracks are a bonus for the\n// panel it opens. The full config is an expensive way to learn a sequence\n// adapter: hg38 is 2.1MB against minimal's 300KB, hg19 1.35MB against 57KB,\n// hs1 603KB against 12KB, and the parse is followed by MST instantiating every\n// track config in it on the main thread (hg38 595 against 33, hs1 624 against\n// 7). hg38 alone names 239 distinct mate assemblies across its 239 synteny\n// tracks, so a session that opens a few of them pays this several times over.\n//\n// What minimal.json costs is the mate genome's long tail \u2014 conservation,\n// expression, the rest of the hub. Those are still one \"Add connection\" away\n// on the full config url, and nothing about this panel implied they were\n// coming. GenArk hubs have no minimal.json and don't need one; their whole\n// config is ~40KB.\nexport function getConfigUrls(assemblyName: string) {\n if (!/^[\\w.]+$/.test(assemblyName)) {\n return []\n }\n if (assemblyName.startsWith('GCA_') || assemblyName.startsWith('GCF_')) {\n const url = getGenArkConfigUrl(assemblyName)\n return url ? [url] : []\n }\n const base = `https://jbrowse.org/ucsc/${assemblyName}`\n return [`${base}/minimal.json`, `${base}/config.json`]\n}\n", "import { getConfigUrls } from './configUrls'\n\ninterface Description {\n assembly: HubAssembly\n geneAdapter?: Record<string, unknown>\n}\n\ninterface HubAssembly {\n name: string\n aliases?: string[]\n}\n\ninterface HubConfig {\n assemblies?: HubAssembly[]\n tracks?: { trackId: string; adapter?: Record<string, unknown> }[]\n}\n\n// jb2hubs' defaultGeneTrackId order, which also picks the track minimal.json\n// keeps and a hub genome's default session opens\nconst GENE_TRACK_SUFFIXES = [\n 'ncbiRefSeq',\n 'ncbiRefSeqCurated',\n 'ncbiGene',\n 'refGene',\n 'ensGene',\n 'augustusGene',\n 'xenoRefGene',\n]\n\n// A TwoBit adapter's bare `chromSizes` resolves against the `baseUri` beside\n// its `uri`, so rewriting each `uri` alone sent jb2hubs' relative chrom.sizes\n// to the page's origin\nfunction withBaseUri<T>(value: T, base: string): T {\n if (Array.isArray(value)) {\n return value.map(item => withBaseUri(item, base)) as T\n }\n if (typeof value === 'object' && value !== null) {\n const entries = Object.entries(value).map(([key, item]) => [\n key,\n withBaseUri(item, base),\n ])\n return Object.fromEntries(\n typeof (value as { uri?: unknown }).uri === 'string' &&\n !('baseUri' in value)\n ? [...entries, ['baseUri', base]]\n : entries,\n ) as T\n }\n return value\n}\n\nexport function describeFromConfig(\n config: HubConfig,\n assemblyName: string,\n configUrl: string,\n): Description | undefined {\n const assembly = config.assemblies?.find(\n a => a.name === assemblyName || a.aliases?.includes(assemblyName),\n )\n if (!assembly) {\n return undefined\n }\n const tracks = new Map(config.tracks?.map(track => [track.trackId, track]))\n const geneAdapter = GENE_TRACK_SUFFIXES.map(\n suffix => tracks.get(`${assembly.name}-${suffix}`)?.adapter,\n ).find(adapter => adapter !== undefined)\n return {\n assembly: withBaseUri(assembly, configUrl),\n geneAdapter: geneAdapter && withBaseUri(geneAdapter, configUrl),\n }\n}\n\n// throws on anything but a found config or a 404, so only a definitive\n// answer is cached\nasync function fetchDescription(assemblyName: string) {\n for (const url of getConfigUrls(assemblyName)) {\n const response = await fetch(url)\n if (response.ok) {\n const config = (await response.json()) as HubConfig\n return describeFromConfig(config, assemblyName, url)\n }\n if (response.status !== 404) {\n throw new Error(`${url}: HTTP ${response.status}`)\n }\n }\n return undefined\n}\n\nconst descriptions = new Map<string, Promise<Description | undefined>>()\n\nfunction describe(assemblyName: string) {\n let description = descriptions.get(assemblyName)\n if (!description) {\n description = fetchDescription(assemblyName).catch((error: unknown) => {\n descriptions.delete(assemblyName)\n console.error(error)\n return undefined\n })\n descriptions.set(assemblyName, description)\n }\n return description\n}\n\n/**\n * Core-describeAssemblies: the assembly config and gene track adapter the\n * hosted config of each named genome holds, read without connecting it. A\n * name another plugin already described, or one no hosted config could hold,\n * is left alone\n */\nexport async function describeAssemblies(\n described: unknown,\n assemblyNames: unknown,\n) {\n const before =\n typeof described === 'object' && described !== null ? described : {}\n const names = Array.isArray(assemblyNames)\n ? assemblyNames.filter((name): name is string => typeof name === 'string')\n : []\n const answers = await Promise.all(\n names\n .filter(\n name => !Object.hasOwn(before, name) && getConfigUrls(name).length > 0,\n )\n .map(async name => [name, await describe(name)] as const),\n )\n return {\n ...before,\n ...Object.fromEntries(\n answers.filter(([, description]) => description !== undefined),\n ),\n }\n}\n", "// Trigger a browser download of `blob` as `filename`. Mirrors the anchor-download\n// path of @jbrowse/core's saveAs: the deferred revoke avoids canceling the\n// download before the browser has read the blob (the read is async in some\n// browsers). Inlined until a published core release exports saveAs from its util.\nexport function saveAs(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.rel = 'noopener'\n anchor.click()\n setTimeout(() => {\n URL.revokeObjectURL(url)\n }, 40000)\n}\n\nfunction asObjArray(value: unknown): Record<string, unknown>[] {\n return Array.isArray(value) ? (value as Record<string, unknown>[]) : []\n}\n\n// Merges two lists of config objects by an id key, with `overrides` winning so\n// a session-scoped track/assembly that shadows a config one (same id) replaces\n// it rather than duplicating.\nfunction mergeById(\n base: Record<string, unknown>[],\n overrides: Record<string, unknown>[],\n key: string,\n): Record<string, unknown>[] {\n const merged = new Map<unknown, Record<string, unknown>>()\n for (const item of [...base, ...overrides]) {\n merged.set(item[key], item)\n }\n return [...merged.values()]\n}\n\n// Builds a desktop `.jbrowse` snapshot (a config plus a defaultSession) from a\n// web root config and its live session. Session-scoped tracks/assemblies are\n// hoisted into the config arrays so they open as first-class config entries in\n// desktop; the rest of the session becomes the defaultSession. Web sessions are\n// always UriLocation-based, so the result is fully portable to desktop.\nexport function toDesktopSnapshot(\n jbrowse: Record<string, unknown>,\n session: Record<string, unknown>,\n): Record<string, unknown> {\n const { sessionTracks, sessionAssemblies, ...defaultSession } = session\n return {\n ...jbrowse,\n tracks: mergeById(\n asObjArray(jbrowse.tracks),\n asObjArray(sessionTracks),\n 'trackId',\n ),\n assemblies: mergeById(\n asObjArray(jbrowse.assemblies),\n asObjArray(sessionAssemblies),\n 'name',\n ),\n defaultSession,\n }\n}\n", "{\n \"version\": \"1.0.16\",\n \"license\": \"MIT\",\n \"name\": \"@cmdcolin/jbrowse-plugin-hubs\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/GMOD/jbrowse-plugin-hubs.git\"\n },\n \"keywords\": [\n \"jbrowse\",\n \"jbrowse2\"\n ],\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.esm.js\",\n \"typings\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"clean\": \"rimraf dist\",\n \"start\": \"node esbuild.mjs --watch\",\n \"test\": \"echo 'no tests'\",\n \"format\": \"pnpm prettier --write .\",\n \"prebuild\": \"pnpm clean\",\n \"build\": \"tsc && NODE_ENV=production node esbuild.mjs\",\n \"lint\": \"eslint src --report-unused-disable-directives --max-warnings 0\",\n \"prepack\": \"pnpm build\",\n \"postversion\": \"git push --follow-tags\",\n \"preversion\": \"pnpm lint && pnpm build && pnpm host-compat\",\n \"host-compat\": \"node scripts/host-compat-probe.mjs --bundle dist/jbrowse-plugin-hubs.umd.production.min.js\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@fal-works/esbuild-plugin-global-externals\": \"^2.1.2\",\n \"@jbrowse/core\": \"^4.3.0\",\n \"@jbrowse/mobx-state-tree\": \"^5.11.1\",\n \"@mui/material\": \"^7.3.11\",\n \"@mui/system\": \"^7.3.11\",\n \"@mui/x-data-grid\": \"^8.29.1\",\n \"@types/node\": \"^25.9.3\",\n \"@types/react\": \"^19.2.17\",\n \"@typescript-eslint/eslint-plugin\": \"^8.61.1\",\n \"@typescript-eslint/parser\": \"^8.61.1\",\n \"esbuild\": \"^0.27.7\",\n \"eslint\": \"^10.5.0\",\n \"eslint-plugin-import-x\": \"^4.16.2\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.1.1\",\n \"eslint-plugin-unicorn\": \"^64.0.0\",\n \"mobx\": \"^6.16.1\",\n \"mobx-react\": \"^9.2.2\",\n \"prettier\": \"^3.8.4\",\n \"pretty-bytes\": \"^7.1.0\",\n \"puppeteer-core\": \"^25.4.0\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"rimraf\": \"^6.1.3\",\n \"rxjs\": \"^7.8.2\",\n \"serve\": \"^14.2.6\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.61.1\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n"],
5
- "mappings": "gpBAAA,IAAAA,EAAAC,EAAA,CAAAC,EAAAC,IAAA,CAAAA,EAAO,QAAU,eAAe,sBAAsB,ICAtD,IAAAC,EAAAC,EAAA,CAAAC,EAAAC,IAAA,CAAAA,EAAO,QAAU,eAAe,oBAAoB,ICApD,IAAAC,EAAAC,EAAA,CAAAC,EAAAC,IAAA,CAAAA,EAAO,QAAU,eAAe,iBAAiB,ICAjD,IAAAC,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,IAAAC,EAAmB,OACnBC,EAAkD,OAClDC,EAAqC,OCFrC,SAASC,EAAmBC,EAAmB,CAC7C,GAAM,CAACC,EAAMC,CAAI,EAAIF,EAAU,MAAM,GAAG,EACxC,GAAI,CAACE,EACH,OAEF,IAAMC,EAAQD,EAAK,MAAM,SAAS,EAClC,GAAI,CAACC,GAASA,EAAM,OAAS,EAC3B,OAEF,GAAM,CAACC,EAAIC,EAAIC,CAAE,EAAIH,EACrB,MAAO,mCAAmCF,CAAI,IAAIG,CAAE,IAAIC,CAAE,IAAIC,CAAE,IAAIN,CAAS,cAC/E,CAsBO,SAASO,EAAcC,EAAsB,CAClD,GAAI,CAAC,WAAW,KAAKA,CAAY,EAC/B,MAAO,CAAC,EAEV,GAAIA,EAAa,WAAW,MAAM,GAAKA,EAAa,WAAW,MAAM,EAAG,CACtE,IAAMC,EAAMV,EAAmBS,CAAY,EAC3C,OAAOC,EAAM,CAACA,CAAG,EAAI,CAAC,CACxB,CACA,IAAMR,EAAO,4BAA4BO,CAAY,GACrD,MAAO,CAAC,GAAGP,CAAI,gBAAiB,GAAGA,CAAI,cAAc,CACvD,CCxBA,IAAMS,EAAsB,CAC1B,aACA,oBACA,WACA,UACA,UACA,eACA,aACF,EAKA,SAASC,EAAeC,EAAUC,EAAiB,CACjD,GAAI,MAAM,QAAQD,CAAK,EACrB,OAAOA,EAAM,IAAIE,GAAQH,EAAYG,EAAMD,CAAI,CAAC,EAElD,GAAI,OAAOD,GAAU,UAAYA,IAAU,KAAM,CAC/C,IAAMG,EAAU,OAAO,QAAQH,CAAK,EAAE,IAAI,CAAC,CAACI,EAAKF,CAAI,IAAM,CACzDE,EACAL,EAAYG,EAAMD,CAAI,CACxB,CAAC,EACD,OAAO,OAAO,YACZ,OAAQD,EAA4B,KAAQ,UAC1C,EAAE,YAAaA,GACb,CAAC,GAAGG,EAAS,CAAC,UAAWF,CAAI,CAAC,EAC9BE,CACN,CACF,CACA,OAAOH,CACT,CAEO,SAASK,EACdC,EACAC,EACAC,EACyB,CACzB,IAAMC,EAAWH,EAAO,YAAY,KAClCI,GAAKA,EAAE,OAASH,GAAgBG,EAAE,SAAS,SAASH,CAAY,CAClE,EACA,GAAI,CAACE,EACH,OAEF,IAAME,EAAS,IAAI,IAAIL,EAAO,QAAQ,IAAIM,GAAS,CAACA,EAAM,QAASA,CAAK,CAAC,CAAC,EACpEC,EAAcf,EAAoB,IACtCgB,GAAUH,EAAO,IAAI,GAAGF,EAAS,IAAI,IAAIK,CAAM,EAAE,GAAG,OACtD,EAAE,KAAKC,GAAWA,IAAY,MAAS,EACvC,MAAO,CACL,SAAUhB,EAAYU,EAAUD,CAAS,EACzC,YAAaK,GAAed,EAAYc,EAAaL,CAAS,CAChE,CACF,CAIA,eAAeQ,EAAiBT,EAAsB,CACpD,QAAWU,KAAOC,EAAcX,CAAY,EAAG,CAC7C,IAAMY,EAAW,MAAM,MAAMF,CAAG,EAChC,GAAIE,EAAS,GAAI,CACf,IAAMb,EAAU,MAAMa,EAAS,KAAK,EACpC,OAAOd,EAAmBC,EAAQC,EAAcU,CAAG,CACrD,CACA,GAAIE,EAAS,SAAW,IACtB,MAAM,IAAI,MAAM,GAAGF,CAAG,UAAUE,EAAS,MAAM,EAAE,CAErD,CAEF,CAEA,IAAMC,EAAe,IAAI,IAEzB,SAASC,EAASd,EAAsB,CACtC,IAAIe,EAAcF,EAAa,IAAIb,CAAY,EAC/C,OAAKe,IACHA,EAAcN,EAAiBT,CAAY,EAAE,MAAOgB,GAAmB,CACrEH,EAAa,OAAOb,CAAY,EAChC,QAAQ,MAAMgB,CAAK,CAErB,CAAC,EACDH,EAAa,IAAIb,EAAce,CAAW,GAErCA,CACT,CAQA,eAAsBE,EACpBC,EACAC,EACA,CACA,IAAMC,EACJ,OAAOF,GAAc,UAAYA,IAAc,KAAOA,EAAY,CAAC,EAC/DG,EAAQ,MAAM,QAAQF,CAAa,EACrCA,EAAc,OAAQG,GAAyB,OAAOA,GAAS,QAAQ,EACvE,CAAC,EACCC,EAAU,MAAM,QAAQ,IAC5BF,EACG,OACCC,GAAQ,CAAC,OAAO,OAAOF,EAAQE,CAAI,GAAKX,EAAcW,CAAI,EAAE,OAAS,CACvE,EACC,IAAI,MAAMA,GAAQ,CAACA,EAAM,MAAMR,EAASQ,CAAI,CAAC,CAAU,CAC5D,EACA,MAAO,CACL,GAAGF,EACH,GAAG,OAAO,YACRG,EAAQ,OAAO,CAAC,CAAC,CAAER,CAAW,IAAMA,IAAgB,MAAS,CAC/D,CACF,CACF,CC/HO,SAASS,EAAOC,EAAYC,EAAkB,CACnD,IAAMC,EAAM,IAAI,gBAAgBF,CAAI,EAC9BG,EAAS,SAAS,cAAc,GAAG,EACzCA,EAAO,KAAOD,EACdC,EAAO,SAAWF,EAClBE,EAAO,IAAM,WACbA,EAAO,MAAM,EACb,WAAW,IAAM,CACf,IAAI,gBAAgBD,CAAG,CACzB,EAAG,GAAK,CACV,CAEA,SAASE,EAAWC,EAA2C,CAC7D,OAAO,MAAM,QAAQA,CAAK,EAAKA,EAAsC,CAAC,CACxE,CAKA,SAASC,EACPC,EACAC,EACAC,EAC2B,CAC3B,IAAMC,EAAS,IAAI,IACnB,QAAWC,IAAQ,CAAC,GAAGJ,EAAM,GAAGC,CAAS,EACvCE,EAAO,IAAIC,EAAKF,CAAG,EAAGE,CAAI,EAE5B,MAAO,CAAC,GAAGD,EAAO,OAAO,CAAC,CAC5B,CAOO,SAASE,EACdC,EACAC,EACyB,CACzB,GAAM,CAAE,cAAAC,EAAe,kBAAAC,EAAmB,GAAGC,CAAe,EAAIH,EAChE,MAAO,CACL,GAAGD,EACH,OAAQP,EACNF,EAAWS,EAAQ,MAAM,EACzBT,EAAWW,CAAa,EACxB,SACF,EACA,WAAYT,EACVF,EAAWS,EAAQ,UAAU,EAC7BT,EAAWY,CAAiB,EAC5B,MACF,EACA,eAAAC,CACF,CACF,CC1DE,IAAAC,EAAW,SJqBb,SAASC,EAAuBC,EAA+B,CAC7D,GAAM,CAAE,QAAAC,CAAQ,KAAI,WAAwCD,CAAO,EAC7DE,EAAOC,KACX,eAAqCF,CAAO,KAC5C,eAAqCD,CAAO,CAC9C,EACAI,EACE,IAAI,KAAK,CAAC,KAAK,UAAUF,EAAM,KAAM,CAAC,CAAC,EAAG,CAAE,KAAM,kBAAmB,CAAC,EACtE,iBACF,CACF,CA2BA,IAAMG,EAAY,IAAI,QAEtB,SAASC,EAAcN,EAAkBO,EAAsB,CAC7D,IAAIC,EAAQH,EAAU,IAAIL,CAAO,EAKjC,OAJKQ,IACHA,EAAQ,IAAI,IACZH,EAAU,IAAIL,EAASQ,CAAK,GAE1BA,EAAM,IAAID,CAAY,EACjB,IAETC,EAAM,IAAID,CAAY,EACf,GACT,CAMA,eAAeE,EACbT,EACAO,EACAG,EACA,CACA,IAAMC,EAAe,UAAUJ,CAAY,GAC3C,GACE,EAAAP,EAAQ,YAAY,KAAKY,GAAKA,EAAE,eAAiBD,CAAY,GAC7D,CAACL,EAAcN,EAASO,CAAY,IAItC,QAAWM,KAAOH,EAEhB,IADiB,MAAM,MAAMG,EAAK,CAAE,OAAQ,MAAO,CAAC,GACvC,GAAI,CACf,IAAMC,EAAO,CACX,KAAM,wBACN,IAAAD,EACA,KAAM,QAAQN,CAAY,GAC1B,cAAe,CAACA,CAAY,EAC5B,aAAAI,CACF,EACAX,EAAQ,kBAAkBc,CAAI,EAa9Bd,EAAQ,eAAec,EAAM,CAAE,OAAQ,EAAK,CAAC,EAC7C,MACF,EAEJ,CAEA,IAAqBC,EAArB,cAA8C,EAAAC,OAAO,CACnD,KAAO,mBACP,QAAUC,EAEV,QAAQC,EAA8B,CACpCA,EAAc,oBACZ,kCACA,CAACC,EAAeC,IAAS,CACvB,IAAMpB,EAAUoB,EAAK,QACfb,EAAea,EAAK,aACpBV,EAAOH,EAAec,EAAcd,CAAY,EAAI,CAAC,EAC3D,OAAIP,GAAWO,GAAgBG,EAAK,OAAS,EAkBpCD,EAAsBT,EAASO,EAAcG,CAAI,EAAE,MACvDY,GAAe,CACd,QAAQ,MAAMA,CAAC,CACjB,CACF,EAIKH,CACT,CACF,EAIAD,EAAc,oBACZ,0BACA,CAACK,EAAoBH,IACnBI,EAAmBD,EAAWH,EAAK,aAAa,CACpD,CACF,CAEA,UAAUF,EAA8B,CAItC,GAAI,CAAC,iBAAc,yBAAsBA,EAAc,SAAS,EAY9D,GAAI,CACFA,EAAc,UAAU,aAAa,QAAS,CAC5C,MAAO,sCACP,QAAUlB,GAAkC,CAC1CD,EAAuBC,CAAO,CAChC,CACF,CAAC,CACH,OAASsB,EAAG,CACV,QAAQ,MAAM,kDAAmDA,CAAC,CACpE,CAEJ,CACF",
6
- "names": ["require_Plugin", "__commonJSMin", "exports", "module", "require_util", "__commonJSMin", "exports", "module", "require_mobx_state_tree", "__commonJSMin", "exports", "module", "index_exports", "__export", "HubsViewerPlugin", "import_Plugin", "import_util", "import_mobx_state_tree", "getGenArkConfigUrl", "accession", "base", "rest", "match", "b1", "b2", "b3", "getConfigUrls", "assemblyName", "url", "GENE_TRACK_SUFFIXES", "withBaseUri", "value", "base", "item", "entries", "key", "describeFromConfig", "config", "assemblyName", "configUrl", "assembly", "a", "tracks", "track", "geneAdapter", "suffix", "adapter", "fetchDescription", "url", "getConfigUrls", "response", "descriptions", "describe", "description", "error", "describeAssemblies", "described", "assemblyNames", "before", "names", "name", "answers", "saveAs", "blob", "filename", "url", "anchor", "asObjArray", "value", "mergeById", "base", "overrides", "key", "merged", "item", "toDesktopSnapshot", "jbrowse", "session", "sessionTracks", "sessionAssemblies", "defaultSession", "version", "downloadDesktopSession", "session", "jbrowse", "snap", "toDesktopSnapshot", "saveAs", "attempted", "markAttempted", "assemblyName", "names", "connectIfConfigExists", "uris", "connectionId", "f", "uri", "conf", "HubsViewerPlugin", "Plugin", "version", "pluginManager", "defaultResult", "args", "getConfigUrls", "e", "described", "describeAssemblies"]
4
+ "sourcesContent": ["module.exports = JBrowseExports[\"@jbrowse/core/Plugin\"];", "module.exports = JBrowseExports[\"@jbrowse/core/util\"];", "module.exports = JBrowseExports[\"mobx-state-tree\"];", "import Plugin from '@jbrowse/core/Plugin'\nimport { isAbstractMenuManager, isElectron } from '@jbrowse/core/util'\nimport { getRoot, getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree'\n\nimport { getConfigUrls } from './configUrls'\nimport { describeAssemblies } from './describeAssemblies'\nimport { saveAs, toDesktopSnapshot } from './util'\nimport { version } from '../package.json'\n\nimport type PluginManager from '@jbrowse/core/PluginManager'\nimport type { AbstractSessionModel } from '@jbrowse/core/util'\nimport type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree'\n\ninterface Session {\n makeConnection: (conf: unknown, initialSnapshot?: unknown) => void\n addConnectionConf: (conf: unknown) => void\n connections: { connectionId: string }[]\n}\n\n// jbrowse-web's config node, on every host before 6ddcb6f886 (main, after\n// v5.0.0-beta.20), strips each `baseUri` from its own snapshot (a\n// postProcessor meant for the admin \"save config\" flow), which leaves each\n// relative `uri` bare, and desktop resolves a bare one against the directory\n// the .jbrowse file sits in: ENOENT ~/Downloads/hg38.chromAlias.txt. Its\n// children's snapshots don't pass through that processor, so the config is\n// read from them, baseUris intact, on old hosts and new alike.\nfunction configSnapshot(jbrowse: IAnyStateTreeNode) {\n const node = jbrowse as Record<string, unknown>\n return Object.fromEntries(\n Object.keys(getSnapshot<Record<string, unknown>>(jbrowse)).map(key => {\n const value = node[key]\n return [key, isStateTreeNode(value) ? getSnapshot(value) : value]\n }),\n )\n}\n\n// Serializes the current web session as a desktop `.jbrowse` file. genomes\n// sessions are config-shaped already, so this just folds the live session into\n// a defaultSession and downloads it; desktop opens it via File > Open session.\nfunction downloadDesktopSession(session: AbstractSessionModel) {\n const { jbrowse } = getRoot<{ jbrowse: IAnyStateTreeNode }>(session)\n const snap = toDesktopSnapshot(\n configSnapshot(jbrowse),\n getSnapshot<Record<string, unknown>>(session),\n )\n saveAs(\n new Blob([JSON.stringify(snap, null, 2)], { type: 'application/json' }),\n 'session.jbrowse',\n )\n}\n\n// Every assembly name this plugin has already taken a run at, whether the probe\n// is still in flight or came back with nothing. The extension point fires on an\n// unresolved read, and `get` is read from render paths, so a name that resolves\n// to no hosted config is asked about again and again \u2014 GenArk strain hubs\n// (mouseStrains and friends) live under /hubs/genark/<hub>/<strain>/ and are not\n// at the url guessed from the name, and a session can name an assembly this host\n// has never heard of at all. Clearing this once the probe settled (what an\n// earlier `finally` did) meant the next read re-probed, i.e. one HEAD per render\n// forever for exactly the names nothing can supply.\n//\n// A name that DID resolve is also in here, and is separately deduped by\n// connectionId once the connection exists. Nothing is ever removed within a\n// session: a probe answers a question about a url that does not change within a\n// page load.\n//\n// Keyed by session, because the connection a probe created belongs to the\n// session and goes with it. A flat Set would remember a name across\n// `setSession` and leave the new session unable to resolve a genome the old one\n// had. WeakMap so a replaced session is still collectable.\n//\n// jbrowse-core@main reports each unknown name to the extension point once per\n// session, which makes this redundant there \u2014 but this plugin runs against\n// whatever core the host page shipped, down to the v4.0.0 floor, where it is\n// the only thing standing between a mistyped assembly name and an unbounded\n// request stream.\nconst attempted = new WeakMap<Session, Set<string>>()\n\nfunction markAttempted(session: Session, assemblyName: string) {\n let names = attempted.get(session)\n if (!names) {\n names = new Set()\n attempted.set(session, names)\n }\n if (names.has(assemblyName)) {\n return false\n }\n names.add(assemblyName)\n return true\n}\n\n// Connect to the first of `uris` that exists. Connecting to a config that 404s\n// puts a red error snackbar over a session that is otherwise working, so probe\n// first and stay quiet when there's nothing there \u2014 some other handler, or the\n// session itself, may be supplying the assembly.\nasync function connectIfConfigExists(\n session: Session,\n assemblyName: string,\n uris: string[],\n) {\n const connectionId = `jb2hub-${assemblyName}`\n if (\n session.connections.find(f => f.connectionId === connectionId) ||\n !markAttempted(session, assemblyName)\n ) {\n return\n }\n for (const uri of uris) {\n const response = await fetch(uri, { method: 'HEAD' })\n if (response.ok) {\n const conf = {\n type: 'JB2TrackHubConnection',\n uri,\n name: `conn_${assemblyName}`,\n assemblyNames: [assemblyName],\n connectionId,\n }\n session.addConnectionConf(conf)\n // `silent`: no \"Successfully loaded\" snackbar. Nobody asked for this\n // connection \u2014 it exists because a track referenced an assembly the\n // session didn't have \u2014 so announcing it is noise over whatever the\n // user was doing, and it lands on top of any screenshot of a hub\n // genome. The property is newer than every released core (it landed\n // after v4.3.0) and this plugin runs against whatever core the host\n // page shipped, down to the v4.0.0 floor, but passing it is safe\n // regardless: MST drops an undeclared key off a model snapshot rather\n // than rejecting it (verified against the fork \u2014 the instance is\n // created, the key is neither readable on it nor in its snapshot), so\n // an older core makes the same connection it always did and keeps its\n // toast.\n session.makeConnection(conf, { silent: true })\n return\n }\n }\n}\n\nexport default class HubsViewerPlugin extends Plugin {\n name = 'HubsViewerPlugin'\n version = version\n\n install(pluginManager: PluginManager) {\n pluginManager.addToExtensionPoint(\n 'Core-handleUnrecognizedAssembly',\n (defaultResult, args) => {\n const session = args.session as Session | undefined\n const assemblyName = args.assemblyName as string | undefined\n const uris = assemblyName ? getConfigUrls(assemblyName) : []\n if (session && assemblyName && uris.length > 0) {\n // The probe and the connection it may create land after this returns,\n // which is fine because assemblyManager re-reads reactively once the\n // assembly shows up.\n //\n // Returning the promise rather than the accumulator: a core that\n // knows to look (jbrowse-core > 4.3.0) awaits it in waitForAssembly,\n // which is what lets that wait end on an event instead of a 10s\n // timeout. Nothing observable happens between being asked and the\n // HEAD coming back, so a core with only the session to watch has to\n // guess, and 10s is both too long to fail in and too short for a cold\n // CDN. Older cores fold the return value into an accumulator they\n // then discard, so this is inert there.\n //\n // Nothing else registers on this point (checked across the plugin\n // ecosystem), so replacing the accumulator costs no other plugin its\n // result; if that changes, a handler registered after this one still\n // receives and can pass on whatever it is given.\n return connectIfConfigExists(session, assemblyName, uris).catch(\n (e: unknown) => {\n console.error(e)\n },\n )\n }\n // Pass the accumulator through: this extension point chains handlers, so\n // returning undefined would clobber another plugin's result.\n return defaultResult\n },\n )\n // A multi-way synteny lane whose genome the session lacks asks here for\n // its assembly config and gene track. Cores older than the point never\n // fire it, so this is inert on them\n pluginManager.addToExtensionPoint(\n 'Core-describeAssemblies',\n (described: unknown, args) =>\n describeAssemblies(described, args.assemblyNames),\n )\n }\n\n configure(pluginManager: PluginManager) {\n // jbrowse-web only. In desktop you'd just save the session, and an exported\n // .jbrowse file carries this plugin in its plugins list, so an older desktop\n // would otherwise load and run this menu code when opening that file.\n if (!isElectron && isAbstractMenuManager(pluginManager.rootModel)) {\n // 'Tools', not 'File'. Every released core from v4.0.0 to latest defines\n // the File menu as a thunk and appends with `menu.menuItems.push()`, which\n // throws on a function; the throw escapes configure() and renders the app\n // as an error page rather than costing just this menu item. Because the\n // plugin store serves `latest/` no-cache, that took out every\n // jbrowse.org/ucsc launch on hg38/hg19/mm39/hs1 the moment 1.0.9 shipped.\n // core@main resolves item contributions lazily and accepts either form,\n // but this plugin has to keep working on the releases already in the wild.\n //\n // Belt and braces on the same reasoning: a cosmetic menu item should never\n // be able to cost a user their whole session.\n try {\n pluginManager.rootModel.appendToMenu('Tools', {\n label: 'Download desktop session (.jbrowse)',\n onClick: (session: AbstractSessionModel) => {\n downloadDesktopSession(session)\n },\n })\n } catch (e) {\n console.error('could not add the desktop-session download item', e)\n }\n }\n }\n}\n", "function getGenArkConfigUrl(accession: string) {\n const [base, rest] = accession.split('_')\n if (!rest) {\n return undefined\n }\n const match = rest.match(/.{1,3}/g)\n if (!match || match.length < 3) {\n return undefined\n }\n const [b1, b2, b3] = match\n return `https://jbrowse.org/hubs/genark/${base}/${b1}/${b2}/${b3}/${accession}/config.json`\n}\n\n// Candidate urls for an assembly name, most preferred first. The connection\n// probe and the describe lookup each take the first that exists, so a name with\n// no hosted config anywhere is still answered by staying quiet.\n//\n// A UCSC db gets `minimal.json` ahead of `config.json`. Both carry the same\n// `assemblies` block (minimal.json is a filtered copy of config.json, tracks\n// dropped to NCBI RefSeq / GENCODE / RepeatMasker / gaps), and the assembly is\n// the whole reason this connection exists \u2014 the tracks are a bonus for the\n// panel it opens. The full config is an expensive way to learn a sequence\n// adapter: hg38 is 2.1MB against minimal's 300KB, hg19 1.35MB against 57KB,\n// hs1 603KB against 12KB, and the parse is followed by MST instantiating every\n// track config in it on the main thread (hg38 595 against 33, hs1 624 against\n// 7). hg38 alone names 239 distinct mate assemblies across its 239 synteny\n// tracks, so a session that opens a few of them pays this several times over.\n//\n// What minimal.json costs is the mate genome's long tail \u2014 conservation,\n// expression, the rest of the hub. Those are still one \"Add connection\" away\n// on the full config url, and nothing about this panel implied they were\n// coming. GenArk hubs have no minimal.json and don't need one; their whole\n// config is ~40KB.\nexport function getConfigUrls(assemblyName: string) {\n if (!/^[\\w.]+$/.test(assemblyName)) {\n return []\n }\n if (assemblyName.startsWith('GCA_') || assemblyName.startsWith('GCF_')) {\n const url = getGenArkConfigUrl(assemblyName)\n return url ? [url] : []\n }\n const base = `https://jbrowse.org/ucsc/${assemblyName}`\n return [`${base}/minimal.json`, `${base}/config.json`]\n}\n", "import { getConfigUrls } from './configUrls'\n\ninterface Description {\n assembly: HubAssembly\n geneAdapter?: Record<string, unknown>\n}\n\ninterface HubAssembly {\n name: string\n aliases?: string[]\n}\n\ninterface HubConfig {\n assemblies?: HubAssembly[]\n tracks?: { trackId: string; adapter?: Record<string, unknown> }[]\n}\n\n// jb2hubs' defaultGeneTrackId order, which also picks the track minimal.json\n// keeps and a hub genome's default session opens\nconst GENE_TRACK_SUFFIXES = [\n 'ncbiRefSeq',\n 'ncbiRefSeqCurated',\n 'ncbiGene',\n 'refGene',\n 'ensGene',\n 'augustusGene',\n 'xenoRefGene',\n]\n\n// A TwoBit adapter's bare `chromSizes` resolves against the `baseUri` beside\n// its `uri`, so rewriting each `uri` alone sent jb2hubs' relative chrom.sizes\n// to the page's origin\nfunction withBaseUri<T>(value: T, base: string): T {\n if (Array.isArray(value)) {\n return value.map(item => withBaseUri(item, base)) as T\n }\n if (typeof value === 'object' && value !== null) {\n const entries = Object.entries(value).map(([key, item]) => [\n key,\n withBaseUri(item, base),\n ])\n return Object.fromEntries(\n typeof (value as { uri?: unknown }).uri === 'string' &&\n !('baseUri' in value)\n ? [...entries, ['baseUri', base]]\n : entries,\n ) as T\n }\n return value\n}\n\nexport function describeFromConfig(\n config: HubConfig,\n assemblyName: string,\n configUrl: string,\n): Description | undefined {\n const assembly = config.assemblies?.find(\n a => a.name === assemblyName || a.aliases?.includes(assemblyName),\n )\n if (!assembly) {\n return undefined\n }\n const tracks = new Map(config.tracks?.map(track => [track.trackId, track]))\n const geneAdapter = GENE_TRACK_SUFFIXES.map(\n suffix => tracks.get(`${assembly.name}-${suffix}`)?.adapter,\n ).find(adapter => adapter !== undefined)\n return {\n assembly: withBaseUri(assembly, configUrl),\n geneAdapter: geneAdapter && withBaseUri(geneAdapter, configUrl),\n }\n}\n\n// throws on anything but a found config or a 404, so only a definitive\n// answer is cached\nasync function fetchDescription(assemblyName: string) {\n for (const url of getConfigUrls(assemblyName)) {\n const response = await fetch(url)\n if (response.ok) {\n const config = (await response.json()) as HubConfig\n return describeFromConfig(config, assemblyName, url)\n }\n if (response.status !== 404) {\n throw new Error(`${url}: HTTP ${response.status}`)\n }\n }\n return undefined\n}\n\nconst descriptions = new Map<string, Promise<Description | undefined>>()\n\nfunction describe(assemblyName: string) {\n let description = descriptions.get(assemblyName)\n if (!description) {\n description = fetchDescription(assemblyName).catch((error: unknown) => {\n descriptions.delete(assemblyName)\n console.error(error)\n return undefined\n })\n descriptions.set(assemblyName, description)\n }\n return description\n}\n\n/**\n * Core-describeAssemblies: the assembly config and gene track adapter the\n * hosted config of each named genome holds, read without connecting it. A\n * name another plugin already described, or one no hosted config could hold,\n * is left alone\n */\nexport async function describeAssemblies(\n described: unknown,\n assemblyNames: unknown,\n) {\n const before =\n typeof described === 'object' && described !== null ? described : {}\n const names = Array.isArray(assemblyNames)\n ? assemblyNames.filter((name): name is string => typeof name === 'string')\n : []\n const answers = await Promise.all(\n names\n .filter(\n name => !Object.hasOwn(before, name) && getConfigUrls(name).length > 0,\n )\n .map(async name => [name, await describe(name)] as const),\n )\n return {\n ...before,\n ...Object.fromEntries(\n answers.filter(([, description]) => description !== undefined),\n ),\n }\n}\n", "// Trigger a browser download of `blob` as `filename`. Mirrors the anchor-download\n// path of @jbrowse/core's saveAs: the deferred revoke avoids canceling the\n// download before the browser has read the blob (the read is async in some\n// browsers). Inlined until a published core release exports saveAs from its util.\nexport function saveAs(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.rel = 'noopener'\n anchor.click()\n setTimeout(() => {\n URL.revokeObjectURL(url)\n }, 40000)\n}\n\nfunction asObjArray(value: unknown): Record<string, unknown>[] {\n return Array.isArray(value) ? (value as Record<string, unknown>[]) : []\n}\n\n// Merges two lists of config objects by an id key, with `overrides` winning so\n// a session-scoped track/assembly that shadows a config one (same id) replaces\n// it rather than duplicating.\nfunction mergeById(\n base: Record<string, unknown>[],\n overrides: Record<string, unknown>[],\n key: string,\n): Record<string, unknown>[] {\n const merged = new Map<unknown, Record<string, unknown>>()\n for (const item of [...base, ...overrides]) {\n merged.set(item[key], item)\n }\n return [...merged.values()]\n}\n\n// Builds a desktop `.jbrowse` snapshot (a config plus a defaultSession) from a\n// web root config and its live session. Session-scoped tracks/assemblies are\n// hoisted into the config arrays so they open as first-class config entries in\n// desktop; the rest of the session becomes the defaultSession. A relative `uri`\n// is only portable with the `baseUri` beside it, so `jbrowse` must keep them.\nexport function toDesktopSnapshot(\n jbrowse: Record<string, unknown>,\n session: Record<string, unknown>,\n): Record<string, unknown> {\n const { sessionTracks, sessionAssemblies, ...defaultSession } = session\n return {\n ...jbrowse,\n tracks: mergeById(\n asObjArray(jbrowse.tracks),\n asObjArray(sessionTracks),\n 'trackId',\n ),\n assemblies: mergeById(\n asObjArray(jbrowse.assemblies),\n asObjArray(sessionAssemblies),\n 'name',\n ),\n defaultSession,\n }\n}\n", "{\n \"version\": \"1.0.17\",\n \"license\": \"MIT\",\n \"name\": \"@cmdcolin/jbrowse-plugin-hubs\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/GMOD/jbrowse-plugin-hubs.git\"\n },\n \"keywords\": [\n \"jbrowse\",\n \"jbrowse2\"\n ],\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.esm.js\",\n \"typings\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"clean\": \"rimraf dist\",\n \"start\": \"node esbuild.mjs --watch\",\n \"test\": \"echo 'no tests'\",\n \"format\": \"pnpm prettier --write .\",\n \"prebuild\": \"pnpm clean\",\n \"build\": \"tsc && NODE_ENV=production node esbuild.mjs\",\n \"lint\": \"eslint src --report-unused-disable-directives --max-warnings 0\",\n \"prepack\": \"pnpm build\",\n \"postversion\": \"git push --follow-tags\",\n \"preversion\": \"pnpm lint && pnpm build && pnpm host-compat\",\n \"host-compat\": \"node scripts/host-compat-probe.mjs --bundle dist/jbrowse-plugin-hubs.umd.production.min.js\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@fal-works/esbuild-plugin-global-externals\": \"^2.1.2\",\n \"@jbrowse/core\": \"^4.3.0\",\n \"@jbrowse/mobx-state-tree\": \"^5.11.1\",\n \"@mui/material\": \"^7.3.11\",\n \"@mui/system\": \"^7.3.11\",\n \"@mui/x-data-grid\": \"^8.29.1\",\n \"@types/node\": \"^25.9.3\",\n \"@types/react\": \"^19.2.17\",\n \"@typescript-eslint/eslint-plugin\": \"^8.61.1\",\n \"@typescript-eslint/parser\": \"^8.61.1\",\n \"esbuild\": \"^0.27.7\",\n \"eslint\": \"^10.5.0\",\n \"eslint-plugin-import-x\": \"^4.16.2\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.1.1\",\n \"eslint-plugin-unicorn\": \"^64.0.0\",\n \"mobx\": \"^6.16.1\",\n \"mobx-react\": \"^9.2.2\",\n \"prettier\": \"^3.8.4\",\n \"pretty-bytes\": \"^7.1.0\",\n \"puppeteer-core\": \"^25.4.0\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"rimraf\": \"^6.1.3\",\n \"rxjs\": \"^7.8.2\",\n \"serve\": \"^14.2.6\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.61.1\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["require_Plugin", "__commonJSMin", "exports", "module", "require_util", "__commonJSMin", "exports", "module", "require_mobx_state_tree", "__commonJSMin", "exports", "module", "index_exports", "__export", "HubsViewerPlugin", "import_Plugin", "import_util", "import_mobx_state_tree", "getGenArkConfigUrl", "accession", "base", "rest", "match", "b1", "b2", "b3", "getConfigUrls", "assemblyName", "url", "GENE_TRACK_SUFFIXES", "withBaseUri", "value", "base", "item", "entries", "key", "describeFromConfig", "config", "assemblyName", "configUrl", "assembly", "a", "tracks", "track", "geneAdapter", "suffix", "adapter", "fetchDescription", "url", "getConfigUrls", "response", "descriptions", "describe", "description", "error", "describeAssemblies", "described", "assemblyNames", "before", "names", "name", "answers", "saveAs", "blob", "filename", "url", "anchor", "asObjArray", "value", "mergeById", "base", "overrides", "key", "merged", "item", "toDesktopSnapshot", "jbrowse", "session", "sessionTracks", "sessionAssemblies", "defaultSession", "version", "configSnapshot", "jbrowse", "node", "key", "value", "downloadDesktopSession", "session", "snap", "toDesktopSnapshot", "saveAs", "attempted", "markAttempted", "assemblyName", "names", "connectIfConfigExists", "uris", "connectionId", "f", "uri", "conf", "HubsViewerPlugin", "Plugin", "version", "pluginManager", "defaultResult", "args", "getConfigUrls", "e", "described", "describeAssemblies"]
7
7
  }
package/dist/util.js CHANGED
@@ -29,8 +29,8 @@ function mergeById(base, overrides, key) {
29
29
  // Builds a desktop `.jbrowse` snapshot (a config plus a defaultSession) from a
30
30
  // web root config and its live session. Session-scoped tracks/assemblies are
31
31
  // hoisted into the config arrays so they open as first-class config entries in
32
- // desktop; the rest of the session becomes the defaultSession. Web sessions are
33
- // always UriLocation-based, so the result is fully portable to desktop.
32
+ // desktop; the rest of the session becomes the defaultSession. A relative `uri`
33
+ // is only portable with the `baseUri` beside it, so `jbrowse` must keep them.
34
34
  export function toDesktopSnapshot(jbrowse, session) {
35
35
  const { sessionTracks, sessionAssemblies, ...defaultSession } = session;
36
36
  return {
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,2EAA2E;AAC3E,2EAA2E;AAC3E,kFAAkF;AAClF,MAAM,UAAU,MAAM,CAAC,IAAU,EAAE,QAAgB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IAC1C,MAAM,CAAC,IAAI,GAAG,GAAG,CAAA;IACjB,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,MAAM,CAAC,GAAG,GAAG,UAAU,CAAA;IACvB,MAAM,CAAC,KAAK,EAAE,CAAA;IACd,UAAU,CAAC,GAAG,EAAE;QACd,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC,EAAE,KAAK,CAAC,CAAA;AACX,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAmC,CAAC,CAAC,CAAC,EAAE,CAAA;AACzE,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,8BAA8B;AAC9B,SAAS,SAAS,CAChB,IAA+B,EAC/B,SAAoC,EACpC,GAAW;IAEX,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoC,CAAA;IAC1D,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAC/B,OAAgC,EAChC,OAAgC;IAEhC,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAA;IACvE,OAAO;QACL,GAAG,OAAO;QACV,MAAM,EAAE,SAAS,CACf,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAC1B,UAAU,CAAC,aAAa,CAAC,EACzB,SAAS,CACV;QACD,UAAU,EAAE,SAAS,CACnB,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,EAC9B,UAAU,CAAC,iBAAiB,CAAC,EAC7B,MAAM,CACP;QACD,cAAc;KACf,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,2EAA2E;AAC3E,2EAA2E;AAC3E,kFAAkF;AAClF,MAAM,UAAU,MAAM,CAAC,IAAU,EAAE,QAAgB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IAC1C,MAAM,CAAC,IAAI,GAAG,GAAG,CAAA;IACjB,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,MAAM,CAAC,GAAG,GAAG,UAAU,CAAA;IACvB,MAAM,CAAC,KAAK,EAAE,CAAA;IACd,UAAU,CAAC,GAAG,EAAE;QACd,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC,EAAE,KAAK,CAAC,CAAA;AACX,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAmC,CAAC,CAAC,CAAC,EAAE,CAAA;AACzE,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,8BAA8B;AAC9B,SAAS,SAAS,CAChB,IAA+B,EAC/B,SAAoC,EACpC,GAAW;IAEX,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoC,CAAA;IAC1D,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB,CAC/B,OAAgC,EAChC,OAAgC;IAEhC,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAA;IACvE,OAAO;QACL,GAAG,OAAO;QACV,MAAM,EAAE,SAAS,CACf,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAC1B,UAAU,CAAC,aAAa,CAAC,EACzB,SAAS,CACV;QACD,UAAU,EAAE,SAAS,CACnB,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,EAC9B,UAAU,CAAC,iBAAiB,CAAC,EAC7B,MAAM,CACP;QACD,cAAc;KACf,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.16",
2
+ "version": "1.0.17",
3
3
  "license": "MIT",
4
4
  "name": "@cmdcolin/jbrowse-plugin-hubs",
5
5
  "repository": {
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Plugin from '@jbrowse/core/Plugin'
2
2
  import { isAbstractMenuManager, isElectron } from '@jbrowse/core/util'
3
- import { getRoot, getSnapshot } from '@jbrowse/mobx-state-tree'
3
+ import { getRoot, getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree'
4
4
 
5
5
  import { getConfigUrls } from './configUrls'
6
6
  import { describeAssemblies } from './describeAssemblies'
@@ -17,13 +17,30 @@ interface Session {
17
17
  connections: { connectionId: string }[]
18
18
  }
19
19
 
20
+ // jbrowse-web's config node, on every host before 6ddcb6f886 (main, after
21
+ // v5.0.0-beta.20), strips each `baseUri` from its own snapshot (a
22
+ // postProcessor meant for the admin "save config" flow), which leaves each
23
+ // relative `uri` bare, and desktop resolves a bare one against the directory
24
+ // the .jbrowse file sits in: ENOENT ~/Downloads/hg38.chromAlias.txt. Its
25
+ // children's snapshots don't pass through that processor, so the config is
26
+ // read from them, baseUris intact, on old hosts and new alike.
27
+ function configSnapshot(jbrowse: IAnyStateTreeNode) {
28
+ const node = jbrowse as Record<string, unknown>
29
+ return Object.fromEntries(
30
+ Object.keys(getSnapshot<Record<string, unknown>>(jbrowse)).map(key => {
31
+ const value = node[key]
32
+ return [key, isStateTreeNode(value) ? getSnapshot(value) : value]
33
+ }),
34
+ )
35
+ }
36
+
20
37
  // Serializes the current web session as a desktop `.jbrowse` file. genomes
21
38
  // sessions are config-shaped already, so this just folds the live session into
22
39
  // a defaultSession and downloads it; desktop opens it via File > Open session.
23
40
  function downloadDesktopSession(session: AbstractSessionModel) {
24
41
  const { jbrowse } = getRoot<{ jbrowse: IAnyStateTreeNode }>(session)
25
42
  const snap = toDesktopSnapshot(
26
- getSnapshot<Record<string, unknown>>(jbrowse),
43
+ configSnapshot(jbrowse),
27
44
  getSnapshot<Record<string, unknown>>(session),
28
45
  )
29
46
  saveAs(
package/src/util.ts CHANGED
@@ -36,8 +36,8 @@ function mergeById(
36
36
  // Builds a desktop `.jbrowse` snapshot (a config plus a defaultSession) from a
37
37
  // web root config and its live session. Session-scoped tracks/assemblies are
38
38
  // hoisted into the config arrays so they open as first-class config entries in
39
- // desktop; the rest of the session becomes the defaultSession. Web sessions are
40
- // always UriLocation-based, so the result is fully portable to desktop.
39
+ // desktop; the rest of the session becomes the defaultSession. A relative `uri`
40
+ // is only portable with the `baseUri` beside it, so `jbrowse` must keep them.
41
41
  export function toDesktopSnapshot(
42
42
  jbrowse: Record<string, unknown>,
43
43
  session: Record<string, unknown>,