diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 034f0bfb65..7bd89be58b 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -106,7 +106,34 @@ jobs:
- name: Typecheck code
run: pnpm typecheck
- name: Run tests
+ id: tests
run: pnpm test-ci
+ continue-on-error: true
+ - name: Upload jest image snapshot diffs to S3
+ if: steps.tests.outcome == 'failure'
+ run: |
+ SNAPSHOTS_DIR="products/jbrowse-web/src/tests/__image_snapshots__/__diff_output__"
+ S3_PATH="s3://jbrowse.org/demos/imagediff/${{ github.run_id }}"
+
+ if ls ${SNAPSHOTS_DIR}/*.png 1> /dev/null 2>&1; then
+ echo "Uploading jest image snapshot diffs to S3..."
+ aws s3 cp ${SNAPSHOTS_DIR}/ ${S3_PATH}/ --recursive --exclude "*" --include "*.png"
+
+ echo ""
+ echo "============================================"
+ echo "JEST SNAPSHOT DIFF IMAGES UPLOADED TO S3"
+ echo "============================================"
+ for file in ${SNAPSHOTS_DIR}/*.png; do
+ filename=$(basename "$file")
+ echo "https://jbrowse.org/demos/imagediff/${{ github.run_id }}/${filename}"
+ done
+ echo "============================================"
+ else
+ echo "No jest snapshot diff files found"
+ fi
+ - name: Fail if tests failed
+ if: steps.tests.outcome == 'failure'
+ run: exit 1
- name: Pack artifacts for component tests
run: node --experimental-strip-types scripts/pack.ts
- name: Test build
diff --git a/component_tests/app-vite/cypress/plugins/index.js b/component_tests/app-vite/cypress/plugins/index.mjs
similarity index 95%
rename from component_tests/app-vite/cypress/plugins/index.js
rename to component_tests/app-vite/cypress/plugins/index.mjs
index 38cbdf2021..4399850abd 100644
--- a/component_tests/app-vite/cypress/plugins/index.js
+++ b/component_tests/app-vite/cypress/plugins/index.mjs
@@ -16,7 +16,7 @@
* @type {Cypress.PluginConfig}
*/
-module.exports = (on, config) => {
+export default (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
diff --git a/component_tests/app-vite/src/main.tsx b/component_tests/app-vite/src/main.tsx
index 711e6d1474..3b83bb9272 100644
--- a/component_tests/app-vite/src/main.tsx
+++ b/component_tests/app-vite/src/main.tsx
@@ -1,11 +1,11 @@
-import React from 'react'
+import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App'
const root = createRoot(document.getElementById('root')!)
root.render(
-
+
- ,
+ ,
)
diff --git a/component_tests/app-vite/tsconfig.node.json b/component_tests/app-vite/tsconfig.node.json
index 0d3d71446a..821cf1a225 100644
--- a/component_tests/app-vite/tsconfig.node.json
+++ b/component_tests/app-vite/tsconfig.node.json
@@ -6,7 +6,7 @@
"skipLibCheck": true,
/* Bundler mode */
- "moduleResolution": "bundler",
+ "moduleResolution": "node",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
diff --git a/component_tests/cgv-vite/cypress/plugins/index.js b/component_tests/cgv-vite/cypress/plugins/index.mjs
similarity index 95%
rename from component_tests/cgv-vite/cypress/plugins/index.js
rename to component_tests/cgv-vite/cypress/plugins/index.mjs
index 38cbdf2021..4399850abd 100644
--- a/component_tests/cgv-vite/cypress/plugins/index.js
+++ b/component_tests/cgv-vite/cypress/plugins/index.mjs
@@ -16,7 +16,7 @@
* @type {Cypress.PluginConfig}
*/
-module.exports = (on, config) => {
+export default (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
diff --git a/component_tests/cgv-vite/src/main.tsx b/component_tests/cgv-vite/src/main.tsx
index 711e6d1474..3b83bb9272 100644
--- a/component_tests/cgv-vite/src/main.tsx
+++ b/component_tests/cgv-vite/src/main.tsx
@@ -1,11 +1,11 @@
-import React from 'react'
+import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App'
const root = createRoot(document.getElementById('root')!)
root.render(
-
+
- ,
+ ,
)
diff --git a/component_tests/cgv-vite/tsconfig.node.json b/component_tests/cgv-vite/tsconfig.node.json
index 0d3d71446a..821cf1a225 100644
--- a/component_tests/cgv-vite/tsconfig.node.json
+++ b/component_tests/cgv-vite/tsconfig.node.json
@@ -6,7 +6,7 @@
"skipLibCheck": true,
/* Bundler mode */
- "moduleResolution": "bundler",
+ "moduleResolution": "node",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
diff --git a/component_tests/lgv-vite/cypress/plugins/index.js b/component_tests/lgv-vite/cypress/plugins/index.mjs
similarity index 95%
rename from component_tests/lgv-vite/cypress/plugins/index.js
rename to component_tests/lgv-vite/cypress/plugins/index.mjs
index 38cbdf2021..4399850abd 100644
--- a/component_tests/lgv-vite/cypress/plugins/index.js
+++ b/component_tests/lgv-vite/cypress/plugins/index.mjs
@@ -16,7 +16,7 @@
* @type {Cypress.PluginConfig}
*/
-module.exports = (on, config) => {
+export default (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
diff --git a/component_tests/lgv-vite/src/main.tsx b/component_tests/lgv-vite/src/main.tsx
index 711e6d1474..3b83bb9272 100644
--- a/component_tests/lgv-vite/src/main.tsx
+++ b/component_tests/lgv-vite/src/main.tsx
@@ -1,11 +1,11 @@
-import React from 'react'
+import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App'
const root = createRoot(document.getElementById('root')!)
root.render(
-
+
- ,
+ ,
)
diff --git a/component_tests/lgv-vite/tsconfig.node.json b/component_tests/lgv-vite/tsconfig.node.json
index 0d3d71446a..821cf1a225 100644
--- a/component_tests/lgv-vite/tsconfig.node.json
+++ b/component_tests/lgv-vite/tsconfig.node.json
@@ -6,7 +6,7 @@
"skipLibCheck": true,
/* Bundler mode */
- "moduleResolution": "bundler",
+ "moduleResolution": "node",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 3936346194..0db6b2e6fe 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -26,6 +26,7 @@ export default defineConfig(
'babel.config.cjs',
'eslint.config.mjs',
'products/**/webpack.config.js',
+ 'products/**/webpack.config.mjs',
'**/.storybook',
'**/output-version.js',
'**/umd_plugin.js',
diff --git a/package.json b/package.json
index 3688282bc2..d16280dbac 100644
--- a/package.json
+++ b/package.json
@@ -106,7 +106,6 @@
"dotenv": "^17.2.3",
"electron": "40.0.0",
"electron-builder": "^25.1.8",
- "electron-mock-ipc": "^0.3.14",
"eslint": "^9.39.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-node": "^11.1.0",
diff --git a/packages/__mocks__/electron.ts b/packages/__mocks__/electron.ts
deleted file mode 100644
index aba9b89991..0000000000
--- a/packages/__mocks__/electron.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import createIPCMock from 'electron-mock-ipc'
-const { ipcMain, ipcRenderer } = createIPCMock()
-
-// @ts-expect-error
-window.require = () => {
- return {
- ipcRenderer,
- ipcMain,
- }
-}
-
-export { ipcMain, ipcRenderer }
diff --git a/packages/app-core/package.json b/packages/app-core/package.json
index d64391cb27..ee53819d0a 100644
--- a/packages/app-core/package.json
+++ b/packages/app-core/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/app-core",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 code shared between the 'full featured' apps e.g. jbrowse-web and jbrowse-desktop",
"keywords": [
"jbrowse",
diff --git a/packages/core/.storybook/main.js b/packages/core/.storybook/main.mjs
similarity index 89%
rename from packages/core/.storybook/main.js
rename to packages/core/.storybook/main.mjs
index 52a1d5b4b4..57ba2fde26 100644
--- a/packages/core/.storybook/main.js
+++ b/packages/core/.storybook/main.mjs
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-essentials'],
framework: {
@@ -14,7 +14,7 @@ module.exports = {
test: /\.(ts|tsx|js|jsx)$/,
use: [
{
- loader: require.resolve('babel-loader'),
+ loader: 'babel-loader',
options: {
rootMode: 'upward',
presets: ['@babel/preset-react'],
diff --git a/packages/core/DEVELOPERS.md b/packages/core/DEVELOPERS.md
new file mode 100644
index 0000000000..2274a440f5
--- /dev/null
+++ b/packages/core/DEVELOPERS.md
@@ -0,0 +1,88 @@
+# @jbrowse/core Developer Guide
+
+## Package Design
+
+This package has **no main entry point**. It is designed exclusively for subpath
+imports:
+
+```typescript
+// Correct usage
+import PluginManager from '@jbrowse/core/PluginManager'
+import { ConfigurationSchema } from '@jbrowse/core/configuration'
+
+// This will error - no default export
+import '@jbrowse/core' // ERR_PACKAGE_PATH_NOT_EXPORTED
+```
+
+## package.json Structure
+
+This package uses a dual-mode configuration to support both monorepo development
+and external consumers.
+
+### Exports Field
+
+The `exports` field defines subpath imports like `@jbrowse/core/PluginManager`.
+During development, these point to source TypeScript files:
+
+```json
+"exports": {
+ ".": "./src/index.ts",
+ "./PluginManager": "./src/PluginManager.ts"
+}
+```
+
+### publishConfig
+
+When the package is published to npm, the `publishConfig` section overrides the
+exports to point to compiled output:
+
+```json
+"publishConfig": {
+ "exports": {
+ "./PluginManager": {
+ "types": "./esm/PluginManager.d.ts",
+ "import": "./esm/PluginManager.js"
+ }
+ }
+}
+```
+
+### typesVersions (for moduleResolution "node" consumers)
+
+The `exports` field is only supported by TypeScript with `moduleResolution` set
+to `bundler`, `node16`, or `nodenext`. For consumers using the legacy
+`moduleResolution: "node"`, we include a `typesVersions` field in
+`publishConfig`:
+
+```json
+"publishConfig": {
+ "typesVersions": {
+ "*": {
+ "PluginManager": ["esm/PluginManager.d.ts"]
+ }
+ }
+}
+```
+
+This tells TypeScript where to find type declarations for subpath imports even
+when the `exports` field is not being read.
+
+## Generating Exports
+
+The exports, publishConfig.exports, and publishConfig.typesVersions are all
+auto-generated by scanning the codebase for `@jbrowse/core/*` imports:
+
+```bash
+pnpm generate:exports
+```
+
+This script (`scripts/generateExports.mjs`) finds all imports of
+`@jbrowse/core/*` across the monorepo and generates the appropriate mappings.
+
+## Module Resolution Summary
+
+| Consumer Environment | How it resolves `@jbrowse/core/PluginManager` |
+| ---------------------------------- | ----------------------------------------------------- |
+| Monorepo (bundler mode) | Uses `exports` field pointing to `src/*.ts` |
+| External (bundler/node16/nodenext) | Uses `publishConfig.exports` pointing to `esm/*.js` |
+| External (node mode) | Uses `typesVersions` for types, `exports` for runtime |
diff --git a/packages/core/package.json b/packages/core/package.json
index 37498818ff..4e5d5333ef 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -19,10 +19,7 @@
"directory": "packages/core"
},
"author": "JBrowse Team",
- "main": "dist/index.js",
- "types": "dist/index.d.ts",
"exports": {
- ".": "./src/index.ts",
"./BaseFeatureWidget": "./src/BaseFeatureWidget/index.ts",
"./BaseFeatureWidget/BaseFeatureDetail": "./src/BaseFeatureWidget/BaseFeatureDetail/index.tsx",
"./BaseFeatureWidget/BaseFeatureDetail/Attributes": "./src/BaseFeatureWidget/BaseFeatureDetail/Attributes.tsx",
@@ -169,7 +166,6 @@
"@types/file-saver-es": "^2.0.3",
"canvas-sequencer-ts": "^3.1.3",
"canvas2svg": "^1.0.16",
- "colord": "^2.9.3",
"copy-to-clipboard": "^3.3.3",
"deepmerge": "^4.3.1",
"detect-node": "^2.1.0",
@@ -180,7 +176,6 @@
"generic-filehandle2": "^2.0.18",
"idb": "^8.0.3",
"librpc-web-mod": "^2.1.1",
- "load-script": "^2.0.0",
"mobx": "^6.15.0",
"mobx-react": "^9.2.1",
"react-draggable": "^4.5.0",
@@ -193,13 +188,7 @@
},
"publishConfig": {
"access": "public",
- "main": "esm/index.js",
- "types": "esm/index.d.ts",
"exports": {
- ".": {
- "types": "./esm/index.d.ts",
- "import": "./esm/index.js"
- },
"./BaseFeatureWidget": {
"types": "./esm/BaseFeatureWidget/index.d.ts",
"import": "./esm/BaseFeatureWidget/index.js"
@@ -640,6 +629,340 @@
"types": "./esm/util/fileHandleStore.d.ts",
"import": "./esm/util/fileHandleStore.js"
}
+ },
+ "typesVersions": {
+ "*": {
+ "BaseFeatureWidget": [
+ "esm/BaseFeatureWidget/index.d.ts"
+ ],
+ "BaseFeatureWidget/BaseFeatureDetail": [
+ "esm/BaseFeatureWidget/BaseFeatureDetail/index.d.ts"
+ ],
+ "BaseFeatureWidget/BaseFeatureDetail/Attributes": [
+ "esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts"
+ ],
+ "BaseFeatureWidget/BaseFeatureDetail/BaseCard": [
+ "esm/BaseFeatureWidget/BaseFeatureDetail/BaseCard.d.ts"
+ ],
+ "BaseFeatureWidget/BaseFeatureDetail/FeatureDetails": [
+ "esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts"
+ ],
+ "BaseFeatureWidget/BaseFeatureDetail/SimpleField": [
+ "esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts"
+ ],
+ "Plugin": [
+ "esm/Plugin.d.ts"
+ ],
+ "PluginLoader": [
+ "esm/PluginLoader.d.ts"
+ ],
+ "PluginManager": [
+ "esm/PluginManager.d.ts"
+ ],
+ "TextSearch/BaseResults": [
+ "esm/TextSearch/BaseResults.d.ts"
+ ],
+ "TextSearch/TextSearchManager": [
+ "esm/TextSearch/TextSearchManager.d.ts"
+ ],
+ "assemblyManager": [
+ "esm/assemblyManager/index.d.ts"
+ ],
+ "assemblyManager/assembly": [
+ "esm/assemblyManager/assembly.d.ts"
+ ],
+ "assemblyManager/assemblyConfigSchema": [
+ "esm/assemblyManager/assemblyConfigSchema.d.ts"
+ ],
+ "configuration": [
+ "esm/configuration/index.d.ts"
+ ],
+ "data_adapters/BaseAdapter": [
+ "esm/data_adapters/BaseAdapter/index.d.ts"
+ ],
+ "data_adapters/BaseAdapter/BaseOptions": [
+ "esm/data_adapters/BaseAdapter/BaseOptions.d.ts"
+ ],
+ "data_adapters/BaseAdapter/stats": [
+ "esm/data_adapters/BaseAdapter/stats.d.ts"
+ ],
+ "data_adapters/dataAdapterCache": [
+ "esm/data_adapters/dataAdapterCache.d.ts"
+ ],
+ "pluggableElementTypes": [
+ "esm/pluggableElementTypes/index.d.ts"
+ ],
+ "pluggableElementTypes/AdapterType": [
+ "esm/pluggableElementTypes/AdapterType.d.ts"
+ ],
+ "pluggableElementTypes/ConnectionType": [
+ "esm/pluggableElementTypes/ConnectionType.d.ts"
+ ],
+ "pluggableElementTypes/DisplayType": [
+ "esm/pluggableElementTypes/DisplayType.d.ts"
+ ],
+ "pluggableElementTypes/GlyphType": [
+ "esm/pluggableElementTypes/GlyphType.d.ts"
+ ],
+ "pluggableElementTypes/InternetAccountType": [
+ "esm/pluggableElementTypes/InternetAccountType.d.ts"
+ ],
+ "pluggableElementTypes/RpcMethodType": [
+ "esm/pluggableElementTypes/RpcMethodType.d.ts"
+ ],
+ "pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions": [
+ "esm/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions.d.ts"
+ ],
+ "pluggableElementTypes/TextSearchAdapterType": [
+ "esm/pluggableElementTypes/TextSearchAdapterType.d.ts"
+ ],
+ "pluggableElementTypes/TrackType": [
+ "esm/pluggableElementTypes/TrackType.d.ts"
+ ],
+ "pluggableElementTypes/ViewType": [
+ "esm/pluggableElementTypes/ViewType.d.ts"
+ ],
+ "pluggableElementTypes/WidgetType": [
+ "esm/pluggableElementTypes/WidgetType.d.ts"
+ ],
+ "pluggableElementTypes/models": [
+ "esm/pluggableElementTypes/models/index.d.ts"
+ ],
+ "pluggableElementTypes/models/BaseViewModel": [
+ "esm/pluggableElementTypes/models/BaseViewModel.d.ts"
+ ],
+ "pluggableElementTypes/models/baseConnectionConfig": [
+ "esm/pluggableElementTypes/models/baseConnectionConfig.d.ts"
+ ],
+ "pluggableElementTypes/renderers/BoxRendererType": [
+ "esm/pluggableElementTypes/renderers/BoxRendererType.d.ts"
+ ],
+ "pluggableElementTypes/renderers/CircularChordRendererType": [
+ "esm/pluggableElementTypes/renderers/CircularChordRendererType.d.ts"
+ ],
+ "pluggableElementTypes/renderers/FeatureRendererType": [
+ "esm/pluggableElementTypes/renderers/FeatureRendererType.d.ts"
+ ],
+ "pluggableElementTypes/renderers/LayoutSession": [
+ "esm/pluggableElementTypes/renderers/LayoutSession.d.ts"
+ ],
+ "pluggableElementTypes/renderers/RendererType": [
+ "esm/pluggableElementTypes/renderers/RendererType.d.ts"
+ ],
+ "pluggableElementTypes/renderers/ServerSideRendererType": [
+ "esm/pluggableElementTypes/renderers/ServerSideRendererType.d.ts"
+ ],
+ "pluggableElementTypes/renderers/util": [
+ "esm/pluggableElementTypes/renderers/util.d.ts"
+ ],
+ "pluggableElementTypes/renderers/util/serializableFilterChain": [
+ "esm/pluggableElementTypes/renderers/util/serializableFilterChain.d.ts"
+ ],
+ "rpc/RpcManager": [
+ "esm/rpc/RpcManager.d.ts"
+ ],
+ "rpc/coreRpcMethods": [
+ "esm/rpc/coreRpcMethods.d.ts"
+ ],
+ "rpc/methods/util": [
+ "esm/rpc/methods/util.d.ts"
+ ],
+ "ui": [
+ "esm/ui/index.d.ts"
+ ],
+ "ui/AppLogo": [
+ "esm/ui/AppLogo.d.ts"
+ ],
+ "ui/BaseTooltip": [
+ "esm/ui/BaseTooltip.d.ts"
+ ],
+ "ui/CascadingMenuButton": [
+ "esm/ui/CascadingMenuButton.d.ts"
+ ],
+ "ui/ColorPicker": [
+ "esm/ui/ColorPicker.d.ts"
+ ],
+ "ui/ConfirmDialog": [
+ "esm/ui/ConfirmDialog.d.ts"
+ ],
+ "ui/DataGridFlexContainer": [
+ "esm/ui/DataGridFlexContainer.d.ts"
+ ],
+ "ui/Dialog": [
+ "esm/ui/Dialog.d.ts"
+ ],
+ "ui/DraggableDialog": [
+ "esm/ui/DraggableDialog.d.ts"
+ ],
+ "ui/DropDownMenu": [
+ "esm/ui/DropDownMenu.d.ts"
+ ],
+ "ui/EditableTypography": [
+ "esm/ui/EditableTypography.d.ts"
+ ],
+ "ui/ErrorBoundary": [
+ "esm/ui/ErrorBoundary.d.ts"
+ ],
+ "ui/ErrorMessage": [
+ "esm/ui/ErrorMessage.d.ts"
+ ],
+ "ui/ErrorMessageStackTraceDialog": [
+ "esm/ui/ErrorMessageStackTraceDialog.d.ts"
+ ],
+ "ui/Icons": [
+ "esm/ui/Icons.d.ts"
+ ],
+ "ui/LoadingEllipses": [
+ "esm/ui/LoadingEllipses.d.ts"
+ ],
+ "ui/Logo": [
+ "esm/ui/Logo.d.ts"
+ ],
+ "ui/Menu": [
+ "esm/ui/Menu.d.ts"
+ ],
+ "ui/ResizeHandle": [
+ "esm/ui/ResizeHandle.d.ts"
+ ],
+ "ui/SanitizedHTML": [
+ "esm/ui/SanitizedHTML.d.ts"
+ ],
+ "ui/Snackbar": [
+ "esm/ui/Snackbar.d.ts"
+ ],
+ "ui/SnackbarModel": [
+ "esm/ui/SnackbarModel.d.ts"
+ ],
+ "ui/colors": [
+ "esm/ui/colors.d.ts"
+ ],
+ "ui/theme": [
+ "esm/ui/theme.d.ts"
+ ],
+ "util": [
+ "esm/util/index.d.ts"
+ ],
+ "util/Base1DUtils": [
+ "esm/util/Base1DUtils.d.ts"
+ ],
+ "util/Base1DViewModel": [
+ "esm/util/Base1DViewModel.d.ts"
+ ],
+ "util/QuickLRU": [
+ "esm/util/QuickLRU/index.d.ts"
+ ],
+ "util/TimeTraveller": [
+ "esm/util/TimeTraveller.d.ts"
+ ],
+ "util/aborting": [
+ "esm/util/aborting.d.ts"
+ ],
+ "util/analytics": [
+ "esm/util/analytics.d.ts"
+ ],
+ "util/blockTypes": [
+ "esm/util/blockTypes.d.ts"
+ ],
+ "util/calculateDynamicBlocks": [
+ "esm/util/calculateDynamicBlocks.d.ts"
+ ],
+ "util/calculateStaticBlocks": [
+ "esm/util/calculateStaticBlocks.d.ts"
+ ],
+ "util/color": [
+ "esm/util/color/index.d.ts"
+ ],
+ "util/colord": [
+ "esm/util/colord.d.ts"
+ ],
+ "util/compositeMap": [
+ "esm/util/compositeMap.d.ts"
+ ],
+ "util/convertCodingSequenceToPeptides": [
+ "esm/util/convertCodingSequenceToPeptides.d.ts"
+ ],
+ "util/flatbush": [
+ "esm/util/flatbush/index.d.ts"
+ ],
+ "util/formatFastaStrings": [
+ "esm/util/formatFastaStrings.d.ts"
+ ],
+ "util/io": [
+ "esm/util/io/index.d.ts"
+ ],
+ "util/io/RemoteFileWithRangeCache": [
+ "esm/util/io/RemoteFileWithRangeCache.d.ts"
+ ],
+ "util/jexlStrings": [
+ "esm/util/jexlStrings.d.ts"
+ ],
+ "util/layouts": [
+ "esm/util/layouts/index.d.ts"
+ ],
+ "util/layouts/BaseLayout": [
+ "esm/util/layouts/BaseLayout.d.ts"
+ ],
+ "util/layouts/GranularRectLayout": [
+ "esm/util/layouts/GranularRectLayout.d.ts"
+ ],
+ "util/librpc": [
+ "esm/util/librpc.d.ts"
+ ],
+ "util/mst-reflection": [
+ "esm/util/mst-reflection.d.ts"
+ ],
+ "util/offscreenCanvasPonyfill": [
+ "esm/util/offscreenCanvasPonyfill.d.ts"
+ ],
+ "util/offscreenCanvasUtils": [
+ "esm/util/offscreenCanvasUtils.d.ts"
+ ],
+ "util/parseLineByLine": [
+ "esm/util/parseLineByLine.d.ts"
+ ],
+ "util/range": [
+ "esm/util/range.d.ts"
+ ],
+ "util/rxjs": [
+ "esm/util/rxjs.d.ts"
+ ],
+ "util/simpleFeature": [
+ "esm/util/simpleFeature.d.ts"
+ ],
+ "util/stats": [
+ "esm/util/stats.d.ts"
+ ],
+ "util/stopToken": [
+ "esm/util/stopToken.d.ts"
+ ],
+ "util/tracks": [
+ "esm/util/tracks.d.ts"
+ ],
+ "util/tss-react": [
+ "esm/util/tss-react/index.d.ts"
+ ],
+ "util/types": [
+ "esm/util/types/index.d.ts"
+ ],
+ "util/types/mst": [
+ "esm/util/types/mst.d.ts"
+ ],
+ "util/useMeasure": [
+ "esm/util/useMeasure.d.ts"
+ ],
+ "ui/ReturnToImportFormDialog": [
+ "esm/ui/ReturnToImportFormDialog.d.ts"
+ ],
+ "util/nanoid": [
+ "esm/util/nanoid.d.ts"
+ ],
+ "ReExports/list": [
+ "esm/ReExports/list.d.ts"
+ ],
+ "util/fileHandleStore": [
+ "esm/util/fileHandleStore.d.ts"
+ ]
+ }
}
},
"sideEffects": false
diff --git a/packages/core/scripts/generateExports.mjs b/packages/core/scripts/generateExports.mjs
index e52ccd4965..a575f32143 100644
--- a/packages/core/scripts/generateExports.mjs
+++ b/packages/core/scripts/generateExports.mjs
@@ -98,16 +98,17 @@ console.log(`Found ${imports.length} unique @jbrowse/core import paths`)
// Generate dev exports (pointing to src)
// Using simple string format since import/require point to same .ts file
-const devExports = {
- '.': './src/index.ts',
-}
+// Note: No "." entry - this package is designed for subpath imports only
+const devExports = {}
// Generate publish exports (pointing to esm)
-const publishExports = {
- '.': {
- types: './esm/index.d.ts',
- import: './esm/index.js',
- },
+// Note: No "." entry - this package is designed for subpath imports only
+const publishExports = {}
+
+// Generate typesVersions for moduleResolution "node" consumers
+// This allows TypeScript to resolve subpath imports even without exports field support
+const typesVersions = {
+ '*': {},
}
for (const entry of imports) {
@@ -121,6 +122,14 @@ for (const entry of imports) {
types: `./esm${outPath.replace('.js', '.d.ts')}`,
import: `./esm${outPath}`,
}
+
+ // typesVersions uses paths without leading './' and maps to array of paths
+ const typesVersionsKey = exportPath.slice(2) // remove './'
+ if (typesVersionsKey) {
+ typesVersions['*'][typesVersionsKey] = [
+ `esm${outPath.replace('.js', '.d.ts')}`,
+ ]
+ }
}
// Read package.json
@@ -135,6 +144,7 @@ if (!packageJson.publishConfig) {
packageJson.publishConfig = {}
}
packageJson.publishConfig.exports = publishExports
+packageJson.publishConfig.typesVersions = typesVersions
// Write back
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`)
@@ -143,3 +153,6 @@ console.log(`Generated ${Object.keys(devExports).length} dev export entries`)
console.log(
`Generated ${Object.keys(publishExports).length} publish export entries`,
)
+console.log(
+ `Generated ${Object.keys(typesVersions['*']).length} typesVersions entries`,
+)
diff --git a/packages/core/src/PluginLoader.ts b/packages/core/src/PluginLoader.ts
index 6eb4a4af65..28afadf9a8 100644
--- a/packages/core/src/PluginLoader.ts
+++ b/packages/core/src/PluginLoader.ts
@@ -1,5 +1,3 @@
-import domLoadScript from 'load-script'
-
import Plugin from './Plugin.ts'
import ReExports from './ReExports/index.ts'
import { isElectron } from './util/index.ts'
@@ -71,14 +69,18 @@ export interface CJSPluginDefinition {
}
function promisifiedLoadScript(src: string) {
- return new Promise((resolve, reject) => {
- domLoadScript(src, (err, script) => {
- if (err) {
- reject(err)
- } else {
- resolve(script.src)
- }
- })
+ return new Promise((resolve, reject) => {
+ const script = document.createElement('script')
+ script.type = 'text/javascript'
+ script.async = true
+ script.src = src
+ script.onload = () => {
+ resolve(script.src)
+ }
+ script.onerror = () => {
+ reject(new Error(`Failed to load script: ${src}`))
+ }
+ document.head.append(script)
})
}
diff --git a/packages/core/src/util/IntervalTree.test.ts b/packages/core/src/util/IntervalTree.test.ts
new file mode 100644
index 0000000000..fa9b5622a7
--- /dev/null
+++ b/packages/core/src/util/IntervalTree.test.ts
@@ -0,0 +1,243 @@
+/**
+ * Tests for vendored IntervalTree
+ * Based on tests from @flatten-js/interval-tree
+ */
+
+import { IntervalTree } from './IntervalTree.ts'
+
+describe('IntervalTree', () => {
+ it('creates new instance', () => {
+ const tree = new IntervalTree()
+ expect(tree).toBeInstanceOf(IntervalTree)
+ })
+
+ it('inserts one entry with numeric tuple key', () => {
+ const tree = new IntervalTree()
+ tree.insert([1, 2], 'val')
+ expect(tree.search([1, 2])).toEqual(['val'])
+ })
+
+ it('inserts many entries', () => {
+ const tree = new IntervalTree()
+ const intervals: [number, number][] = [
+ [6, 8],
+ [1, 4],
+ [5, 12],
+ [1, 1],
+ [5, 7],
+ ]
+ for (let i = 0, l = intervals.length; i < l; i++) {
+ tree.insert(intervals[i]!, `val${i}`)
+ }
+ // [1,1] intersects both [1,1] and [1,4]
+ expect(tree.search([1, 1])).toContain('val3')
+ expect(tree.search([1, 1])).toContain('val1')
+ expect(tree.search([6, 8])).toContain('val0')
+ })
+
+ it('searches interval and returns array of values', () => {
+ const tree = new IntervalTree()
+ const intervals: [number, number][] = [
+ [6, 8],
+ [1, 4],
+ [5, 12],
+ [1, 1],
+ [5, 7],
+ ]
+ for (let i = 0, l = intervals.length; i < l; i++) {
+ tree.insert(intervals[i]!, `val${i}`)
+ }
+ expect(tree.search([2, 3])).toEqual(['val1'])
+ })
+
+ it('returns empty array when search interval does not intersect any', () => {
+ const tree = new IntervalTree()
+ const intervals: [number, number][] = [
+ [6, 8],
+ [1, 2],
+ [7, 12],
+ [1, 1],
+ [5, 7],
+ ]
+ for (let i = 0, l = intervals.length; i < l; i++) {
+ tree.insert(intervals[i]!, `val${i}`)
+ }
+ expect(tree.search([3, 4])).toEqual([])
+ })
+
+ it('buckets multiple values for identical keys', () => {
+ const tree = new IntervalTree()
+ tree.insert([2, 5], 10)
+ tree.insert([2, 5], 20)
+ tree.insert([2, 5], 30)
+ tree.insert([2, 5], 40)
+ tree.insert([2, 5], 50)
+
+ const results = tree.search([2, 5])
+ expect(results).toContain(10)
+ expect(results).toContain(20)
+ expect(results).toContain(30)
+ expect(results).toContain(40)
+ expect(results).toContain(50)
+ expect(results).toHaveLength(5)
+ })
+
+ it('handles storing 0 as a value', () => {
+ const tree = new IntervalTree()
+ tree.insert([0, 0], 0)
+ tree.insert([0, 0], 1)
+
+ const results = tree.search([0, 0])
+ expect(results).toEqual([0, 1])
+ })
+
+ it('stores falsy values: 0, false, NaN, null', () => {
+ const tree = new IntervalTree()
+ tree.insert([0, 0], 0)
+ tree.insert([0, 0], false)
+ tree.insert([0, 0], NaN)
+ tree.insert([0, 0], null)
+
+ const results = tree.search([0, 0])
+ expect(results).toHaveLength(4)
+ expect(results).toContain(0)
+ expect(results).toContain(false)
+ expect(results).toContain(null)
+ expect(results.some(v => Number.isNaN(v))).toBe(true)
+ })
+
+ it('stores custom objects', () => {
+ interface Item {
+ name: string
+ value: number
+ }
+ const tree = new IntervalTree- ()
+ const data: Item[] = [
+ { name: 'A', value: 111 },
+ { name: 'B', value: 333 },
+ { name: 'C', value: 222 },
+ ]
+
+ tree.insert([2, 5], data[0]!)
+ tree.insert([2, 5], data[1]!)
+ tree.insert([2, 5], data[2]!)
+
+ const results = tree.search([2, 5])
+ expect(results).toContain(data[0])
+ expect(results).toContain(data[1])
+ expect(results).toContain(data[2])
+ })
+
+ it('normalizes reversed intervals', () => {
+ const tree = new IntervalTree()
+ tree.insert([8, 2], 'reversed')
+ tree.insert([2, 8], 'normal')
+
+ // Both should be stored under [2, 8] and retrieved together
+ const results = tree.search([3, 5])
+ expect(results).toContain('reversed')
+ expect(results).toContain('normal')
+ })
+
+ it('handles overlapping intervals correctly', () => {
+ const tree = new IntervalTree()
+ tree.insert([1, 5], 'a')
+ tree.insert([3, 8], 'b')
+ tree.insert([6, 10], 'c')
+ tree.insert([12, 15], 'd')
+
+ expect(tree.search([4, 4])).toEqual(['a', 'b'])
+ expect(tree.search([7, 7])).toEqual(['b', 'c'])
+ expect(tree.search([11, 11])).toEqual([])
+ expect(tree.search([1, 15])).toEqual(['a', 'b', 'c', 'd'])
+ })
+
+ it('works with genomic-style intervals', () => {
+ const tree = new IntervalTree()
+ tree.insert([1000, 2000], 'gene1')
+ tree.insert([1500, 3000], 'gene2')
+ tree.insert([5000, 6000], 'gene3')
+
+ expect(tree.search([1700, 1800])).toEqual(['gene1', 'gene2'])
+ expect(tree.search([4000, 4500])).toEqual([])
+ expect(tree.search([5500, 5600])).toEqual(['gene3'])
+ })
+
+ it('returns empty array when searching empty tree', () => {
+ const tree = new IntervalTree()
+ expect(tree.search([1, 10])).toEqual([])
+ })
+
+ it('handles adjacent non-overlapping intervals', () => {
+ const tree = new IntervalTree()
+ tree.insert([1, 5], 'a')
+ tree.insert([6, 10], 'b')
+
+ expect(tree.search([5, 5])).toEqual(['a'])
+ expect(tree.search([6, 6])).toEqual(['b'])
+ // gap between them
+ expect(tree.search([5.5, 5.5])).toEqual([])
+ })
+
+ it('handles intervals that touch at exactly one point', () => {
+ const tree = new IntervalTree()
+ tree.insert([1, 5], 'a')
+ tree.insert([5, 10], 'b')
+
+ // point 5 is in both intervals
+ expect(tree.search([5, 5])).toContain('a')
+ expect(tree.search([5, 5])).toContain('b')
+ })
+
+ it('handles negative coordinates', () => {
+ const tree = new IntervalTree()
+ tree.insert([-10, -5], 'neg')
+ tree.insert([-3, 3], 'span')
+ tree.insert([5, 10], 'pos')
+
+ expect(tree.search([-7, -6])).toEqual(['neg'])
+ expect(tree.search([0, 0])).toEqual(['span'])
+ expect(tree.search([-20, 20])).toEqual(['neg', 'span', 'pos'])
+ })
+
+ it('handles nested/containing intervals', () => {
+ const tree = new IntervalTree()
+ tree.insert([1, 100], 'outer')
+ tree.insert([25, 75], 'middle')
+ tree.insert([40, 60], 'inner')
+
+ expect(tree.search([50, 50])).toContain('outer')
+ expect(tree.search([50, 50])).toContain('middle')
+ expect(tree.search([50, 50])).toContain('inner')
+ expect(tree.search([10, 20])).toEqual(['outer'])
+ })
+
+ it('handles large coordinates', () => {
+ const tree = new IntervalTree()
+ tree.insert([100000000, 100001000], 'gene1')
+ tree.insert([200000000, 200001000], 'gene2')
+
+ expect(tree.search([100000500, 100000600])).toEqual(['gene1'])
+ expect(tree.search([150000000, 150000000])).toEqual([])
+ })
+
+ it('handles many intervals (stress test)', () => {
+ const tree = new IntervalTree()
+ // insert 1000 intervals
+ for (let i = 0; i < 1000; i++) {
+ tree.insert([i * 10, i * 10 + 5], i)
+ }
+
+ expect(tree.search([500, 505])).toEqual([50])
+ expect(tree.search([0, 10000])).toHaveLength(1000)
+ })
+
+ it('handles single interval tree', () => {
+ const tree = new IntervalTree()
+ tree.insert([5, 10], 'only')
+
+ expect(tree.search([1, 4])).toEqual([])
+ expect(tree.search([7, 8])).toEqual(['only'])
+ expect(tree.search([11, 15])).toEqual([])
+ })
+})
diff --git a/packages/core/src/util/IntervalTree.ts b/packages/core/src/util/IntervalTree.ts
new file mode 100644
index 0000000000..79980291a0
--- /dev/null
+++ b/packages/core/src/util/IntervalTree.ts
@@ -0,0 +1,312 @@
+/**
+ * Vendored and simplified from @flatten-js/interval-tree
+ * https://github.com/nickolanack/flatten-interval-tree
+ * License: MIT
+ * Created by Alex Bol on 3/31/2017.
+ *
+ * Simplified to only support numeric intervals and the subset of API we use:
+ * - constructor, insert, search
+ */
+
+const RB_TREE_COLOR_RED = 1
+const RB_TREE_COLOR_BLACK = 0
+type NodeColor = typeof RB_TREE_COLOR_RED | typeof RB_TREE_COLOR_BLACK
+
+class Interval {
+ constructor(
+ public low: number,
+ public high: number,
+ ) {}
+
+ lessThan(other: Interval) {
+ return (
+ this.low < other.low || (this.low === other.low && this.high < other.high)
+ )
+ }
+
+ equalTo(other: Interval) {
+ return this.low === other.low && this.high === other.high
+ }
+
+ intersects(other: Interval) {
+ return !(this.high < other.low || other.high < this.low)
+ }
+
+ merge(other: Interval) {
+ return new Interval(
+ Math.min(this.low, other.low),
+ Math.max(this.high, other.high),
+ )
+ }
+}
+
+class Node {
+ left: Node | null = null
+ right: Node | null = null
+ parent: Node | null = null
+ color: NodeColor = RB_TREE_COLOR_BLACK
+ key: Interval | undefined
+ values: V[] = []
+ max: Interval | undefined
+
+ constructor(
+ key?: Interval | [number, number],
+ value?: V,
+ left?: Node | null,
+ right?: Node | null,
+ parent?: Node | null,
+ color?: NodeColor,
+ ) {
+ if (left !== undefined) {
+ this.left = left
+ }
+ if (right !== undefined) {
+ this.right = right
+ }
+ if (parent !== undefined) {
+ this.parent = parent
+ }
+ if (color !== undefined) {
+ this.color = color
+ }
+ if (value !== undefined) {
+ this.values.push(value)
+ }
+ if (key !== undefined) {
+ if (Array.isArray(key)) {
+ const [low, high] = key
+ this.key =
+ low <= high ? new Interval(low, high) : new Interval(high, low)
+ } else {
+ this.key = key
+ }
+ this.max = this.key
+ }
+ }
+
+ lessThan(other: Node) {
+ return this.key!.lessThan(other.key!)
+ }
+
+ equalTo(other: Node) {
+ return this.key!.equalTo(other.key!)
+ }
+
+ intersects(other: Node) {
+ return this.key!.intersects(other.key!)
+ }
+
+ updateMax() {
+ this.max = this.key
+ if (this.right?.max && this.max) {
+ this.max = this.max.merge(this.right.max)
+ }
+ if (this.left?.max && this.max) {
+ this.max = this.max.merge(this.left.max)
+ }
+ }
+
+ notIntersectLeftSubtree(searchNode: Node) {
+ if (!this.left) {
+ return true
+ }
+ const high = this.left.max?.high ?? this.left.key!.high
+ return high < searchNode.key!.low
+ }
+
+ notIntersectRightSubtree(searchNode: Node) {
+ if (!this.right) {
+ return true
+ }
+ const low = this.right.max?.low ?? this.right.key!.low
+ return searchNode.key!.high < low
+ }
+}
+
+export class IntervalTree {
+ root: Node | null = null
+ private nilNode = new Node()
+
+ insert(key: [number, number], value: V) {
+ const existing = this.treeSearch(this.root, new Node(key))
+ if (existing) {
+ existing.values.push(value)
+ return existing
+ }
+ const insertNode = new Node(
+ key,
+ value,
+ this.nilNode,
+ this.nilNode,
+ null,
+ RB_TREE_COLOR_RED,
+ )
+ this.treeInsert(insertNode)
+ this.recalcMax(insertNode)
+ return insertNode
+ }
+
+ search(interval: [number, number]): V[] {
+ const searchNode = new Node(interval)
+ const resultNodes: Node[] = []
+ this.treeSearchInterval(this.root, searchNode, resultNodes)
+ const results: V[] = []
+ for (const node of resultNodes) {
+ for (const v of node.values) {
+ results.push(v)
+ }
+ }
+ return results
+ }
+
+ private recalcMax(node: Node) {
+ let current = node
+ while (current.parent != null) {
+ current.parent.updateMax()
+ current = current.parent
+ }
+ }
+
+ private treeInsert(insertNode: Node) {
+ let current: Node | null = this.root
+ let parent: Node | null = null
+
+ if (this.root == null || this.root === this.nilNode) {
+ this.root = insertNode
+ } else {
+ while (current !== this.nilNode) {
+ parent = current!
+ current = insertNode.lessThan(current!) ? current!.left : current!.right
+ }
+ insertNode.parent = parent
+ if (insertNode.lessThan(parent!)) {
+ parent!.left = insertNode
+ } else {
+ parent!.right = insertNode
+ }
+ }
+ this.insertFixup(insertNode)
+ }
+
+ private insertFixup(insertNode: Node) {
+ let current = insertNode
+ while (
+ current !== this.root &&
+ current.parent!.color === RB_TREE_COLOR_RED
+ ) {
+ if (current.parent === current.parent!.parent!.left) {
+ const uncle = current.parent!.parent!.right!
+ if (uncle.color === RB_TREE_COLOR_RED) {
+ current.parent!.color = RB_TREE_COLOR_BLACK
+ uncle.color = RB_TREE_COLOR_BLACK
+ current.parent!.parent!.color = RB_TREE_COLOR_RED
+ current = current.parent!.parent!
+ } else {
+ if (current === current.parent!.right) {
+ current = current.parent!
+ this.rotateLeft(current)
+ }
+ current.parent!.color = RB_TREE_COLOR_BLACK
+ current.parent!.parent!.color = RB_TREE_COLOR_RED
+ this.rotateRight(current.parent!.parent!)
+ }
+ } else {
+ const uncle = current.parent!.parent!.left!
+ if (uncle.color === RB_TREE_COLOR_RED) {
+ current.parent!.color = RB_TREE_COLOR_BLACK
+ uncle.color = RB_TREE_COLOR_BLACK
+ current.parent!.parent!.color = RB_TREE_COLOR_RED
+ current = current.parent!.parent!
+ } else {
+ if (current === current.parent!.left) {
+ current = current.parent!
+ this.rotateRight(current)
+ }
+ current.parent!.color = RB_TREE_COLOR_BLACK
+ current.parent!.parent!.color = RB_TREE_COLOR_RED
+ this.rotateLeft(current.parent!.parent!)
+ }
+ }
+ }
+ this.root!.color = RB_TREE_COLOR_BLACK
+ }
+
+ private treeSearch(
+ node: Node | null,
+ searchNode: Node,
+ ): Node | undefined {
+ if (node == null || node === this.nilNode) {
+ return undefined
+ }
+ if (searchNode.equalTo(node)) {
+ return node
+ }
+ return searchNode.lessThan(node)
+ ? this.treeSearch(node.left, searchNode)
+ : this.treeSearch(node.right, searchNode)
+ }
+
+ private treeSearchInterval(
+ node: Node | null,
+ searchNode: Node,
+ results: Node[],
+ ) {
+ if (node != null && node !== this.nilNode) {
+ if (
+ node.left !== this.nilNode &&
+ !node.notIntersectLeftSubtree(searchNode)
+ ) {
+ this.treeSearchInterval(node.left, searchNode, results)
+ }
+ if (node.intersects(searchNode)) {
+ results.push(node)
+ }
+ if (
+ node.right !== this.nilNode &&
+ !node.notIntersectRightSubtree(searchNode)
+ ) {
+ this.treeSearchInterval(node.right, searchNode, results)
+ }
+ }
+ }
+
+ private rotateLeft(x: Node) {
+ const y = x.right!
+ x.right = y.left
+ if (y.left !== this.nilNode) {
+ y.left!.parent = x
+ }
+ y.parent = x.parent
+ if (x === this.root) {
+ this.root = y
+ } else if (x === x.parent!.left) {
+ x.parent!.left = y
+ } else {
+ x.parent!.right = y
+ }
+ y.left = x
+ x.parent = y
+ x.updateMax()
+ y.updateMax()
+ }
+
+ private rotateRight(y: Node) {
+ const x = y.left!
+ y.left = x.right
+ if (x.right !== this.nilNode) {
+ x.right!.parent = y
+ }
+ x.parent = y.parent
+ if (y === this.root) {
+ this.root = x
+ } else if (y === y.parent!.left) {
+ y.parent!.left = x
+ } else {
+ y.parent!.right = x
+ }
+ x.right = y
+ y.parent = x
+ y.updateMax()
+ x.updateMax()
+ }
+}
diff --git a/packages/core/src/util/colord.ts b/packages/core/src/util/colord.ts
index a916e42b14..f89e304eb4 100644
--- a/packages/core/src/util/colord.ts
+++ b/packages/core/src/util/colord.ts
@@ -1,27 +1,301 @@
-import { colord as colordOriginal, extend } from 'colord'
-import mix from 'colord/plugins/mix'
-import names from 'colord/plugins/names'
+import { namedColorToHex } from './color/cssColorsLevel4.ts'
-import type { AnyColor, Colord as ColordBase } from 'colord'
+interface RGBA {
+ r: number
+ g: number
+ b: number
+ a: number
+}
+
+interface HSLA {
+ h: number
+ s: number
+ l: number
+ a: number
+}
+
+export interface Colord {
+ alpha(): number
+ alpha(value: number): Colord
+ toHex(): string
+ toRgbString(): string
+ toHsl(): HSLA
+ toHslString(): string
+ mix(color: Colord | string, ratio?: number): Colord
+ darken(amount?: number): Colord
+ lighten(amount?: number): Colord
+}
+
+function clamp(value: number, min: number, max: number): number {
+ return Math.max(min, Math.min(max, value))
+}
+
+function round(value: number, precision = 0): number {
+ const mult = 10 ** precision
+ return Math.round(value * mult) / mult
+}
+
+function parseHex(hex: string): RGBA | null {
+ const match = /^#([0-9a-f]{3,8})$/i.exec(hex)
+ if (!match) {
+ return null
+ }
+ const hexStr = match[1]!
+ if (hexStr.length === 3) {
+ return {
+ r: parseInt(hexStr[0]! + hexStr[0], 16),
+ g: parseInt(hexStr[1]! + hexStr[1], 16),
+ b: parseInt(hexStr[2]! + hexStr[2], 16),
+ a: 1,
+ }
+ }
+ if (hexStr.length === 4) {
+ return {
+ r: parseInt(hexStr[0]! + hexStr[0], 16),
+ g: parseInt(hexStr[1]! + hexStr[1], 16),
+ b: parseInt(hexStr[2]! + hexStr[2], 16),
+ a: parseInt(hexStr[3]! + hexStr[3], 16) / 255,
+ }
+ }
+ if (hexStr.length === 6) {
+ return {
+ r: parseInt(hexStr.slice(0, 2), 16),
+ g: parseInt(hexStr.slice(2, 4), 16),
+ b: parseInt(hexStr.slice(4, 6), 16),
+ a: 1,
+ }
+ }
+ if (hexStr.length === 8) {
+ return {
+ r: parseInt(hexStr.slice(0, 2), 16),
+ g: parseInt(hexStr.slice(2, 4), 16),
+ b: parseInt(hexStr.slice(4, 6), 16),
+ a: parseInt(hexStr.slice(6, 8), 16) / 255,
+ }
+ }
+ return null
+}
+
+function parseRgb(str: string): RGBA | null {
+ const match =
+ /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(
+ str,
+ )
+ if (match) {
+ return {
+ r: parseInt(match[1]!, 10),
+ g: parseInt(match[2]!, 10),
+ b: parseInt(match[3]!, 10),
+ a: match[4] ? parseFloat(match[4]) : 1,
+ }
+ }
+ return null
+}
-// Extend Colord interface with mix plugin methods
-export interface Colord extends ColordBase {
- mix(color2: AnyColor | Colord, ratio?: number): Colord
- tints(count?: number): Colord[]
- shades(count?: number): Colord[]
- tones(count?: number): Colord[]
+function parseHsl(str: string): RGBA | null {
+ const match =
+ /^hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(
+ str,
+ )
+ if (match) {
+ const h = parseFloat(match[1]!)
+ const s = parseFloat(match[2]!) / 100
+ const l = parseFloat(match[3]!) / 100
+ const a = match[4] ? parseFloat(match[4]) : 1
+ return { ...hslToRgb(h, s, l), a }
+ }
+ return null
}
-let initialized = false
+function hslToRgb(
+ h: number,
+ s: number,
+ l: number,
+): { r: number; g: number; b: number } {
+ h = ((h % 360) + 360) % 360
+ const c = (1 - Math.abs(2 * l - 1)) * s
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
+ const m = l - c / 2
+
+ let r = 0
+ let g = 0
+ let b = 0
+
+ if (h < 60) {
+ r = c
+ g = x
+ } else if (h < 120) {
+ r = x
+ g = c
+ } else if (h < 180) {
+ g = c
+ b = x
+ } else if (h < 240) {
+ g = x
+ b = c
+ } else if (h < 300) {
+ r = x
+ b = c
+ } else {
+ r = c
+ b = x
+ }
-function ensurePlugins() {
- if (!initialized) {
- extend([mix, names])
- initialized = true
+ return {
+ r: Math.round((r + m) * 255),
+ g: Math.round((g + m) * 255),
+ b: Math.round((b + m) * 255),
}
}
-export function colord(input: Parameters[0]): Colord {
- ensurePlugins()
- return colordOriginal(input) as Colord
+function rgbToHsl(
+ r: number,
+ g: number,
+ b: number,
+): { h: number; s: number; l: number } {
+ r /= 255
+ g /= 255
+ b /= 255
+
+ const max = Math.max(r, g, b)
+ const min = Math.min(r, g, b)
+ const l = (max + min) / 2
+
+ if (max === min) {
+ return { h: 0, s: 0, l }
+ }
+
+ const d = max - min
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
+
+ let h = 0
+ if (max === r) {
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6
+ } else if (max === g) {
+ h = ((b - r) / d + 2) / 6
+ } else {
+ h = ((r - g) / d + 4) / 6
+ }
+
+ return { h: h * 360, s, l }
+}
+
+function parseColor(input: string | { h: number; s: number; l: number }): RGBA {
+ if (typeof input === 'object') {
+ const { h, s, l } = input
+ return { ...hslToRgb(h, s / 100, l / 100), a: 1 }
+ }
+
+ const str = input.trim().toLowerCase()
+
+ const namedHex = namedColorToHex(str)
+ if (namedHex) {
+ return parseHex(namedHex)!
+ }
+
+ if (str === 'transparent') {
+ return { r: 0, g: 0, b: 0, a: 0 }
+ }
+
+ const hex = parseHex(str)
+ if (hex) {
+ return hex
+ }
+
+ const rgb = parseRgb(str)
+ if (rgb) {
+ return rgb
+ }
+
+ const hsl = parseHsl(str)
+ if (hsl) {
+ return hsl
+ }
+
+ return { r: 0, g: 0, b: 0, a: 1 }
+}
+
+function toHex2(n: number): string {
+ return Math.round(clamp(n, 0, 255))
+ .toString(16)
+ .padStart(2, '0')
+}
+
+function createColord(rgba: RGBA): Colord {
+ const obj: Colord = {
+ alpha(value?: number): number | Colord {
+ if (value === undefined) {
+ return rgba.a
+ }
+ return createColord({ ...rgba, a: clamp(value, 0, 1) })
+ },
+
+ toHex(): string {
+ const { r, g, b, a } = rgba
+ if (a < 1) {
+ return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}${toHex2(a * 255)}`
+ }
+ return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}`
+ },
+
+ toRgbString(): string {
+ const { r, g, b, a } = rgba
+ if (a < 1) {
+ return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${round(a, 3)})`
+ }
+ return `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`
+ },
+
+ toHsl(): HSLA {
+ const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b)
+ return {
+ h: round(h, 1),
+ s: round(s * 100, 1),
+ l: round(l * 100, 1),
+ a: rgba.a,
+ }
+ },
+
+ toHslString(): string {
+ const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b)
+ if (rgba.a < 1) {
+ return `hsla(${round(h, 1)}, ${round(s * 100, 1)}%, ${round(l * 100, 1)}%, ${round(rgba.a, 3)})`
+ }
+ return `hsl(${round(h, 1)}, ${round(s * 100, 1)}%, ${round(l * 100, 1)}%)`
+ },
+
+ mix(color2: Colord | string, ratio = 0.5): Colord {
+ const c2 =
+ typeof color2 === 'string'
+ ? parseColor(color2)
+ : parseColor(color2.toHex())
+ const r = rgba.r + (c2.r - rgba.r) * ratio
+ const g = rgba.g + (c2.g - rgba.g) * ratio
+ const b = rgba.b + (c2.b - rgba.b) * ratio
+ const a = rgba.a + (c2.a - rgba.a) * ratio
+ return createColord({ r, g, b, a })
+ },
+
+ darken(amount = 0.1): Colord {
+ const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b)
+ const newL = clamp(l - amount, 0, 1)
+ const rgb = hslToRgb(h, s, newL)
+ return createColord({ ...rgb, a: rgba.a })
+ },
+
+ lighten(amount = 0.1): Colord {
+ const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b)
+ const newL = clamp(l + amount, 0, 1)
+ const rgb = hslToRgb(h, s, newL)
+ return createColord({ ...rgb, a: rgba.a })
+ },
+ } as Colord
+
+ return obj
+}
+
+export function colord(
+ input: string | { h: number; s: number; l: number },
+): Colord {
+ return createColord(parseColor(input))
}
diff --git a/packages/core/src/util/crypto.ts b/packages/core/src/util/crypto.ts
new file mode 100644
index 0000000000..9f956f572e
--- /dev/null
+++ b/packages/core/src/util/crypto.ts
@@ -0,0 +1,306 @@
+// Crypto utilities using Web Crypto API
+// Compatible with crypto-js OpenSSL format for AES encryption
+
+const SALT_PREFIX = 'Salted__'
+
+// MD5 implementation for EVP_BytesToKey (required for crypto-js compatibility)
+function md5(data: Uint8Array): Uint8Array {
+ // MD5 constants
+ const S = [
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5,
+ 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11,
+ 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10,
+ 15, 21,
+ ]
+ const K = [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
+ 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
+ 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
+ 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+ 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
+ 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+ ]
+
+ function leftRotate(x: number, c: number) {
+ return (x << c) | (x >>> (32 - c))
+ }
+
+ // Pre-processing: adding padding bits
+ const originalLength = data.length
+ const bitLength = originalLength * 8
+
+ // Append "1" bit and padding zeros
+ const paddingLength = (56 - ((originalLength + 1) % 64) + 64) % 64
+ const padded = new Uint8Array(originalLength + 1 + paddingLength + 8)
+ padded.set(data)
+ padded[originalLength] = 0x80
+
+ // Append original length in bits as 64-bit little-endian
+ const view = new DataView(padded.buffer)
+ view.setUint32(padded.length - 8, bitLength >>> 0, true)
+ view.setUint32(padded.length - 4, Math.floor(bitLength / 0x100000000), true)
+
+ // Initialize hash values
+ let a0 = 0x67452301
+ let b0 = 0xefcdab89
+ let c0 = 0x98badcfe
+ let d0 = 0x10325476
+
+ // Process each 512-bit chunk
+ for (let i = 0; i < padded.length; i += 64) {
+ const M = new Uint32Array(16)
+ for (let j = 0; j < 16; j++) {
+ M[j] = view.getUint32(i + j * 4, true)
+ }
+
+ let A = a0
+ let B = b0
+ let C = c0
+ let D = d0
+
+ for (let j = 0; j < 64; j++) {
+ let F: number
+ let g: number
+
+ if (j < 16) {
+ F = (B & C) | (~B & D)
+ g = j
+ } else if (j < 32) {
+ F = (D & B) | (~D & C)
+ g = (5 * j + 1) % 16
+ } else if (j < 48) {
+ F = B ^ C ^ D
+ g = (3 * j + 5) % 16
+ } else {
+ F = C ^ (B | ~D)
+ g = (7 * j) % 16
+ }
+
+ F = (F + A + K[j]! + M[g]!) >>> 0
+ A = D
+ D = C
+ C = B
+ B = (B + leftRotate(F, S[j]!)) >>> 0
+ }
+
+ a0 = (a0 + A) >>> 0
+ b0 = (b0 + B) >>> 0
+ c0 = (c0 + C) >>> 0
+ d0 = (d0 + D) >>> 0
+ }
+
+ const result = new Uint8Array(16)
+ const resultView = new DataView(result.buffer)
+ resultView.setUint32(0, a0, true)
+ resultView.setUint32(4, b0, true)
+ resultView.setUint32(8, c0, true)
+ resultView.setUint32(12, d0, true)
+
+ return result
+}
+
+// EVP_BytesToKey - OpenSSL key derivation function used by crypto-js
+function evpBytesToKey(
+ password: Uint8Array,
+ salt: Uint8Array,
+ keyLen: number,
+ ivLen: number,
+): { key: Uint8Array; iv: Uint8Array } {
+ const result = new Uint8Array(keyLen + ivLen)
+ let offset = 0
+ let prevHash: Uint8Array = new Uint8Array(0)
+
+ while (offset < keyLen + ivLen) {
+ const data = new Uint8Array(prevHash.length + password.length + salt.length)
+ data.set(prevHash)
+ data.set(password, prevHash.length)
+ data.set(salt, prevHash.length + password.length)
+ prevHash = md5(data)
+ result.set(
+ prevHash.subarray(0, Math.min(16, keyLen + ivLen - offset)),
+ offset,
+ )
+ offset += 16
+ }
+
+ return {
+ key: result.slice(0, keyLen),
+ iv: result.slice(keyLen, keyLen + ivLen),
+ }
+}
+
+// PKCS7 padding
+function pkcs7Pad(
+ data: Uint8Array,
+ blockSize: number,
+): Uint8Array {
+ const padding = blockSize - (data.length % blockSize)
+ const padded = new Uint8Array(data.length + padding)
+ padded.set(data)
+ padded.fill(padding, data.length)
+ return padded
+}
+
+function pkcs7Unpad(data: Uint8Array): Uint8Array {
+ const padding = data[data.length - 1]!
+ if (padding > 16 || padding === 0) {
+ throw new Error('Invalid padding')
+ }
+ return data.subarray(0, data.length - padding)
+}
+
+// Convert string to Uint8Array (UTF-8)
+function stringToBytes(str: string): Uint8Array {
+ const encoded = new TextEncoder().encode(str)
+ // Return a copy with a fresh ArrayBuffer to satisfy TypeScript's strict typing
+ return encoded.slice()
+}
+
+// Convert Uint8Array to string (UTF-8)
+function bytesToString(bytes: Uint8Array): string {
+ return new TextDecoder().decode(bytes)
+}
+
+// Base64 encode
+function base64Encode(data: Uint8Array): string {
+ let binary = ''
+ for (const byte of data) {
+ binary += String.fromCharCode(byte)
+ }
+ return btoa(binary)
+}
+
+// Base64 decode
+function base64Decode(str: string): Uint8Array {
+ const binary = atob(str)
+ const bytes = new Uint8Array(binary.length)
+ for (let i = 0; i < binary.length; i++) {
+ bytes[i] = binary.charCodeAt(i)
+ }
+ return bytes
+}
+
+/**
+ * AES encrypt using Web Crypto API, compatible with crypto-js OpenSSL format
+ */
+export async function aesEncrypt(
+ plaintext: string,
+ password: string,
+): Promise {
+ const salt = crypto.getRandomValues(new Uint8Array(8))
+ const { key, iv } = evpBytesToKey(stringToBytes(password), salt, 32, 16)
+
+ const cryptoKey = await crypto.subtle.importKey(
+ 'raw',
+ key,
+ { name: 'AES-CBC' },
+ false,
+ ['encrypt'],
+ )
+
+ const paddedData = pkcs7Pad(stringToBytes(plaintext), 16)
+ const encrypted = await crypto.subtle.encrypt(
+ { name: 'AES-CBC', iv },
+ cryptoKey,
+ paddedData,
+ )
+
+ // Format: "Salted__" + salt + ciphertext, then Base64
+ const saltPrefix = stringToBytes(SALT_PREFIX)
+ const result = new Uint8Array(
+ saltPrefix.length + salt.length + encrypted.byteLength,
+ )
+ result.set(saltPrefix)
+ result.set(salt, saltPrefix.length)
+ result.set(new Uint8Array(encrypted), saltPrefix.length + salt.length)
+
+ return base64Encode(result)
+}
+
+/**
+ * AES decrypt using Web Crypto API, compatible with crypto-js OpenSSL format
+ */
+export async function aesDecrypt(
+ ciphertext: string,
+ password: string,
+): Promise {
+ const data = base64Decode(ciphertext)
+
+ // Check for "Salted__" prefix
+ const saltPrefix = stringToBytes(SALT_PREFIX)
+ const hasSalt =
+ data.length > saltPrefix.length &&
+ bytesToString(data.subarray(0, saltPrefix.length)) === SALT_PREFIX
+
+ if (!hasSalt) {
+ throw new Error('Invalid encrypted data format')
+ }
+
+ const salt = data.slice(saltPrefix.length, saltPrefix.length + 8)
+ const encrypted = data.slice(saltPrefix.length + 8)
+
+ const { key, iv } = evpBytesToKey(stringToBytes(password), salt, 32, 16)
+
+ const cryptoKey = await crypto.subtle.importKey(
+ 'raw',
+ key,
+ { name: 'AES-CBC' },
+ false,
+ ['decrypt'],
+ )
+
+ const decrypted = await crypto.subtle.decrypt(
+ { name: 'AES-CBC', iv },
+ cryptoKey,
+ encrypted,
+ )
+
+ return bytesToString(pkcs7Unpad(new Uint8Array(decrypted)))
+}
+
+/**
+ * SHA256 hash using Web Crypto API
+ */
+export async function sha256(data: string): Promise {
+ const encoded = stringToBytes(data)
+ const hashBuffer = await crypto.subtle.digest('SHA-256', encoded)
+ return new Uint8Array(hashBuffer)
+}
+
+/**
+ * Base64 encode a Uint8Array
+ */
+export function toBase64(data: Uint8Array): string {
+ return base64Encode(data)
+}
+
+/**
+ * URL-safe Base64 encode (for OAuth PKCE)
+ */
+export function toBase64Url(data: Uint8Array): string {
+ return base64Encode(data)
+ .replaceAll('+', '-')
+ .replaceAll('/', '_')
+ .replaceAll('=', '')
+}
+
+/**
+ * SHA256 hash and return as Base64 (for OAuth PKCE code challenge)
+ */
+export async function sha256Base64(data: string): Promise {
+ const hash = await sha256(data)
+ return toBase64(hash)
+}
+
+/**
+ * SHA256 hash and return as URL-safe Base64 (for OAuth PKCE code challenge)
+ */
+export async function sha256Base64Url(data: string): Promise {
+ const hash = await sha256(data)
+ return toBase64Url(hash)
+}
diff --git a/packages/core/src/util/index.ts b/packages/core/src/util/index.ts
index 5114cf445b..8fb61868ca 100644
--- a/packages/core/src/util/index.ts
+++ b/packages/core/src/util/index.ts
@@ -58,6 +58,7 @@ export * from './coarseStripHTML.ts'
export * from './offscreenCanvasPonyfill.tsx'
export * from './offscreenCanvasUtils.tsx'
export * from './rpc.ts'
+export * from './crypto.ts'
// WeakMap caches for containing model lookups to avoid repeated tree traversal
const containingDisplayCache = new WeakMap<
@@ -1439,3 +1440,4 @@ export * from './locString.ts'
export * from './stopToken.ts'
export * from './tracks.ts'
export * from './fileHandleStore.ts'
+export { IntervalTree } from './IntervalTree.ts'
diff --git a/packages/embedded-core/package.json b/packages/embedded-core/package.json
index 39836b6a6c..812148b1ae 100644
--- a/packages/embedded-core/package.json
+++ b/packages/embedded-core/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/embedded-core",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 code shared between embedded products",
"keywords": [
"jbrowse",
diff --git a/packages/product-core/package.json b/packages/product-core/package.json
index 9dd68aaf69..4ba78c915e 100644
--- a/packages/product-core/package.json
+++ b/packages/product-core/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/product-core",
"version": "4.0.4",
+ "type": "module",
"sideEffects": false,
"description": "JBrowse 2 code shared between products but not used by plugins",
"keywords": [
diff --git a/packages/sv-core/package.json b/packages/sv-core/package.json
index 4219824f39..998525722b 100644
--- a/packages/sv-core/package.json
+++ b/packages/sv-core/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/sv-core",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 code shared between sv type code",
"keywords": [
"jbrowse",
diff --git a/packages/text-indexing/package.json b/packages/text-indexing/package.json
index cd6f0994a8..72570dbdb6 100644
--- a/packages/text-indexing/package.json
+++ b/packages/text-indexing/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/text-indexing",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 text indexing for desktop",
"keywords": [
"jbrowse",
diff --git a/packages/web-core/package.json b/packages/web-core/package.json
index 190fba5031..6f445c722e 100644
--- a/packages/web-core/package.json
+++ b/packages/web-core/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/web-core",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 code shared between web-app type products",
"keywords": [
"jbrowse",
diff --git a/plugins/alignments/package.json b/plugins/alignments/package.json
index 430fcf1f4c..fe0b22ce0d 100644
--- a/plugins/alignments/package.json
+++ b/plugins/alignments/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-alignments",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 alignments adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/plugins/arc/package.json b/plugins/arc/package.json
index 1e74c61171..616281d188 100644
--- a/plugins/arc/package.json
+++ b/plugins/arc/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-arc",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 arc adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/plugins/authentication/package.json b/plugins/authentication/package.json
index cf8df14d55..066e062ea6 100644
--- a/plugins/authentication/package.json
+++ b/plugins/authentication/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-authentication",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 Authentication",
"keywords": [
"jbrowse",
diff --git a/plugins/authentication/src/OAuthModel/model.tsx b/plugins/authentication/src/OAuthModel/model.tsx
index a0ff9d8f37..4e84c5859b 100644
--- a/plugins/authentication/src/OAuthModel/model.tsx
+++ b/plugins/authentication/src/OAuthModel/model.tsx
@@ -4,10 +4,10 @@ import { isElectron } from '@jbrowse/core/util'
import { types } from '@jbrowse/mobx-state-tree'
import {
- fixup,
generateChallenge,
processError,
processTokenResponse,
+ toBase64Url,
} from './util.ts'
import { getResponseError } from '../util.ts'
@@ -15,18 +15,6 @@ import type { OAuthInternetAccountConfigModel } from './configSchema.ts'
import type { UriLocation } from '@jbrowse/core/util'
import type { Instance } from '@jbrowse/mobx-state-tree'
-// ISC Copyright (c) 2020, Andrea Giammarchi, @WebReflection
-// https://github.com/WebReflection/uint8-to-base64
-function encode(uint8array: Uint8Array) {
- const output = []
-
- for (let i = 0, length = uint8array.length; i < length; i++) {
- output.push(String.fromCharCode(uint8array[i]!))
- }
-
- return btoa(output.join(''))
-}
-
interface OAuthData {
client_id: string
redirect_uri: string
@@ -63,7 +51,7 @@ const stateModelFactory = (configSchema: OAuthInternetAccountConfigModel) => {
if (!codeVerifier) {
const array = new Uint8Array(32)
globalThis.crypto.getRandomValues(array)
- codeVerifier = fixup(encode(array))
+ codeVerifier = toBase64Url(array)
}
return codeVerifier
},
diff --git a/plugins/authentication/src/OAuthModel/util.ts b/plugins/authentication/src/OAuthModel/util.ts
index a199bfacaa..cf61c5278f 100644
--- a/plugins/authentication/src/OAuthModel/util.ts
+++ b/plugins/authentication/src/OAuthModel/util.ts
@@ -1,11 +1,7 @@
-export function fixup(buf: string) {
- return buf.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '')
-}
+import { sha256Base64Url } from '@jbrowse/core/util'
export async function generateChallenge(val: string) {
- const sha256 = await import('crypto-js/sha256').then(f => f.default)
- const Base64 = await import('crypto-js/enc-base64')
- return fixup(Base64.stringify(sha256(val)))
+ return sha256Base64Url(val)
}
// if response is JSON, checks if it needs to remove tokens in error, or just plain throw
@@ -31,3 +27,5 @@ export function processTokenResponse(
}
return data.access_token
}
+
+export { toBase64Url } from '@jbrowse/core/util'
diff --git a/plugins/bed/package.json b/plugins/bed/package.json
index d00da7e73c..d8b9f85ca6 100644
--- a/plugins/bed/package.json
+++ b/plugins/bed/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-bed",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 bed adapters, tracks, etc.",
"keywords": [
"jbrowse",
@@ -31,7 +32,7 @@
"dependencies": {
"@flatten-js/interval-tree": "^2.0.3",
"@gmod/bbi": "^8.1.1",
- "@gmod/bed": "^2.1.7",
+ "@gmod/bed": "^2.1.10",
"@gmod/tabix": "^3.2.2",
"@jbrowse/core": "workspace:^",
"@jbrowse/mobx-state-tree": "^5.5.0",
diff --git a/plugins/bed/src/BedAdapter/BedAdapter.ts b/plugins/bed/src/BedAdapter/BedAdapter.ts
index de40b8de01..cda341f714 100644
--- a/plugins/bed/src/BedAdapter/BedAdapter.ts
+++ b/plugins/bed/src/BedAdapter/BedAdapter.ts
@@ -1,7 +1,10 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import BED from '@gmod/bed'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
-import { SimpleFeature, fetchAndMaybeUnzip } from '@jbrowse/core/util'
+import {
+ IntervalTree,
+ SimpleFeature,
+ fetchAndMaybeUnzip,
+} from '@jbrowse/core/util'
import { openLocation } from '@jbrowse/core/util/io'
import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
diff --git a/plugins/bed/src/BedGraphAdapter/BedGraphAdapter.ts b/plugins/bed/src/BedGraphAdapter/BedGraphAdapter.ts
index b8dd5b8d71..cafcd325c7 100644
--- a/plugins/bed/src/BedGraphAdapter/BedGraphAdapter.ts
+++ b/plugins/bed/src/BedGraphAdapter/BedGraphAdapter.ts
@@ -1,6 +1,9 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
-import { SimpleFeature, fetchAndMaybeUnzip } from '@jbrowse/core/util'
+import {
+ IntervalTree,
+ SimpleFeature,
+ fetchAndMaybeUnzip,
+} from '@jbrowse/core/util'
import { openLocation } from '@jbrowse/core/util/io'
import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
diff --git a/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts b/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts
index 55e107089a..c80fd13356 100644
--- a/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts
+++ b/plugins/bed/src/BedpeAdapter/BedpeAdapter.ts
@@ -1,6 +1,5 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
-import { fetchAndMaybeUnzipText } from '@jbrowse/core/util'
+import { IntervalTree, fetchAndMaybeUnzipText } from '@jbrowse/core/util'
import { openLocation } from '@jbrowse/core/util/io'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
diff --git a/plugins/bed/src/util.ts b/plugins/bed/src/util.ts
index 96523a7e2e..e5b63245b8 100644
--- a/plugins/bed/src/util.ts
+++ b/plugins/bed/src/util.ts
@@ -11,7 +11,7 @@ import {
isUcscTranscript,
} from './generateUcscTranscript.ts'
-import type { MinimalFeature } from './types'
+import type { MinimalFeature } from './types.ts'
import type BED from '@gmod/bed'
function defaultParser(fields: string[], splitLine: string[]) {
diff --git a/plugins/breakpoint-split-view/package.json b/plugins/breakpoint-split-view/package.json
index ce95221df2..d5e844af32 100644
--- a/plugins/breakpoint-split-view/package.json
+++ b/plugins/breakpoint-split-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-breakpoint-split-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 breakpoint detail split view",
"keywords": [
"jbrowse",
diff --git a/plugins/canvas/package.json b/plugins/canvas/package.json
index 9815423f75..be6b4748bb 100644
--- a/plugins/canvas/package.json
+++ b/plugins/canvas/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-canvas",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 plugin for canvas features",
"keywords": [
"jbrowse",
diff --git a/plugins/circular-view/package.json b/plugins/circular-view/package.json
index 7e0f098185..7154a01c9d 100644
--- a/plugins/circular-view/package.json
+++ b/plugins/circular-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-circular-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 circular view",
"keywords": [
"jbrowse",
diff --git a/plugins/comparative-adapters/package.json b/plugins/comparative-adapters/package.json
index 8f1c676336..284b27a076 100644
--- a/plugins/comparative-adapters/package.json
+++ b/plugins/comparative-adapters/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-comparative-adapters",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 comparative adapters",
"keywords": [
"jbrowse",
diff --git a/plugins/config/package.json b/plugins/config/package.json
index 7ac1d258c0..bb51c49fbe 100644
--- a/plugins/config/package.json
+++ b/plugins/config/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-config",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 config utilities",
"keywords": [
"jbrowse",
diff --git a/plugins/data-management/package.json b/plugins/data-management/package.json
index 629947f939..8b16fa2b78 100644
--- a/plugins/data-management/package.json
+++ b/plugins/data-management/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-data-management",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 linear genome view",
"keywords": [
"jbrowse",
diff --git a/plugins/data-management/src/AddConnectionWidget/components/AddConnectionWidget.test.tsx b/plugins/data-management/src/AddConnectionWidget/components/AddConnectionWidget.test.tsx
index 7526d0827f..29858f604d 100644
--- a/plugins/data-management/src/AddConnectionWidget/components/AddConnectionWidget.test.tsx
+++ b/plugins/data-management/src/AddConnectionWidget/components/AddConnectionWidget.test.tsx
@@ -1,8 +1,8 @@
import { ThemeProvider } from '@emotion/react'
import { createJBrowseTheme } from '@jbrowse/core/ui'
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { render } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import AddConnectionWidget2 from './AddConnectionWidget.tsx'
diff --git a/plugins/data-management/src/AddTrackWidget/components/AddTrackWidget.test.tsx b/plugins/data-management/src/AddTrackWidget/components/AddTrackWidget.test.tsx
index 89a83589fc..64b0b69ea3 100644
--- a/plugins/data-management/src/AddTrackWidget/components/AddTrackWidget.test.tsx
+++ b/plugins/data-management/src/AddTrackWidget/components/AddTrackWidget.test.tsx
@@ -1,4 +1,4 @@
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { fireEvent, render } from '@testing-library/react'
import AddTrackWidget from './AddTrackWidget.tsx'
diff --git a/plugins/data-management/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.test.tsx b/plugins/data-management/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.test.tsx
index 4224432fd8..f599536f4f 100644
--- a/plugins/data-management/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.test.tsx
+++ b/plugins/data-management/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.test.tsx
@@ -1,10 +1,10 @@
import { createJBrowseTheme } from '@jbrowse/core/ui'
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { ThemeProvider } from '@mui/material'
import { fireEvent, render } from '@testing-library/react'
import HierarchicalTrackSelector from './HierarchicalTrackSelector.tsx'
-import conf from '../../../../../test_data/test_order/config.json'
+import conf from '../../../../../test_data/test_order/config.json' with { type: 'json' }
import type { HierarchicalTrackSelectorModel } from '../model.ts'
diff --git a/plugins/data-management/src/PluginStoreWidget/components/PluginStoreWidget.test.tsx b/plugins/data-management/src/PluginStoreWidget/components/PluginStoreWidget.test.tsx
index e4df95b3b9..d4fab82106 100644
--- a/plugins/data-management/src/PluginStoreWidget/components/PluginStoreWidget.test.tsx
+++ b/plugins/data-management/src/PluginStoreWidget/components/PluginStoreWidget.test.tsx
@@ -1,10 +1,10 @@
import { DialogQueue } from '@jbrowse/app-core'
import { createJBrowseTheme } from '@jbrowse/core/ui'
import { getParent, getRoot, getSnapshot } from '@jbrowse/mobx-state-tree'
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { ThemeProvider } from '@mui/material'
import { render, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import PluginStoreWidget from './PluginStoreWidget.tsx'
diff --git a/plugins/dotplot-view/package.json b/plugins/dotplot-view/package.json
index fde3836cfc..bb07530f79 100644
--- a/plugins/dotplot-view/package.json
+++ b/plugins/dotplot-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-dotplot-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 dotplot view",
"keywords": [
"jbrowse",
diff --git a/plugins/dotplot-view/src/index.ts b/plugins/dotplot-view/src/index.ts
index 2df65e6c9e..b5ce081f4f 100644
--- a/plugins/dotplot-view/src/index.ts
+++ b/plugins/dotplot-view/src/index.ts
@@ -13,7 +13,7 @@ import LaunchDotplotViewF from './LaunchDotplotView.ts'
import type PluginManager from '@jbrowse/core/PluginManager'
import type { AbstractSessionModel } from '@jbrowse/core/util'
-export type { DotplotImportFormSyntenyOption } from './DotplotView/components/ImportForm/TrackSelector'
+export type { DotplotImportFormSyntenyOption } from './DotplotView/components/ImportForm/TrackSelector.ts'
export default class DotplotPlugin extends Plugin {
name = 'DotplotPlugin'
diff --git a/plugins/gccontent/package.json b/plugins/gccontent/package.json
index fa073fbc5a..69c7dddf58 100644
--- a/plugins/gccontent/package.json
+++ b/plugins/gccontent/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-gccontent",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 gccontent concepts",
"keywords": [
"jbrowse",
diff --git a/plugins/gff3/package.json b/plugins/gff3/package.json
index aed481c7d7..6aa1cfc8d7 100644
--- a/plugins/gff3/package.json
+++ b/plugins/gff3/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-gff3",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 gff3.",
"keywords": [
"jbrowse",
diff --git a/plugins/gff3/src/Gff3Adapter/Gff3Adapter.ts b/plugins/gff3/src/Gff3Adapter/Gff3Adapter.ts
index 0ce1dd850a..ef7d9870e4 100644
--- a/plugins/gff3/src/Gff3Adapter/Gff3Adapter.ts
+++ b/plugins/gff3/src/Gff3Adapter/Gff3Adapter.ts
@@ -1,6 +1,5 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
-import { fetchAndMaybeUnzip } from '@jbrowse/core/util'
+import { IntervalTree, fetchAndMaybeUnzip } from '@jbrowse/core/util'
import { openLocation } from '@jbrowse/core/util/io'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
import SimpleFeature from '@jbrowse/core/util/simpleFeature'
diff --git a/plugins/grid-bookmark/package.json b/plugins/grid-bookmark/package.json
index 675c6811c7..5a17aa9cfd 100644
--- a/plugins/grid-bookmark/package.json
+++ b/plugins/grid-bookmark/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-grid-bookmark",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 grid bookmark widget",
"keywords": [
"jbrowse",
diff --git a/plugins/grid-bookmark/src/GridBookmarkWidget/sessionSharing.ts b/plugins/grid-bookmark/src/GridBookmarkWidget/sessionSharing.ts
index 516d5a12fa..977e1b1e99 100644
--- a/plugins/grid-bookmark/src/GridBookmarkWidget/sessionSharing.ts
+++ b/plugins/grid-bookmark/src/GridBookmarkWidget/sessionSharing.ts
@@ -1,4 +1,6 @@
// duplicated from products/jbrowse-web/src/sessionSharing.ts ; could possibly be moved into a higher directory and shared between the two
+import { aesDecrypt, aesEncrypt } from '@jbrowse/core/util'
+
import { toUrlSafeB64 } from './utils.ts'
// from https://stackoverflow.com/questions/1349404/
@@ -13,18 +15,6 @@ function generateUID(length: number) {
.slice(0, length)
}
-const encrypt = async (text: string, password: string) => {
- const AES = await import('crypto-js/aes')
- return AES.encrypt(text, password).toString()
-}
-
-const decrypt = async (text: string, password: string) => {
- const AES = await import('crypto-js/aes')
- const Utf8 = await import('crypto-js/enc-utf8')
- const bytes = AES.decrypt(text, password)
- return bytes.toString(Utf8)
-}
-
function getErrorMsg(err: string) {
try {
const obj = JSON.parse(err)
@@ -41,7 +31,7 @@ export async function shareSessionToDynamo(
) {
const sess = await toUrlSafeB64(JSON.stringify(session))
const password = generateUID(5)
- const encryptedSession = await encrypt(sess, password)
+ const encryptedSession = await aesEncrypt(sess, password)
const data = new FormData()
data.append('session', encryptedSession)
@@ -79,5 +69,5 @@ export async function readSessionFromDynamo(
}
const json = await response.json()
- return decrypt(json.session, password)
+ return aesDecrypt(json.session, password)
}
diff --git a/plugins/gtf/package.json b/plugins/gtf/package.json
index 69e2c24059..dad5e50bec 100644
--- a/plugins/gtf/package.json
+++ b/plugins/gtf/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-gtf",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 gtf feature adapter",
"keywords": [
"jbrowse",
diff --git a/plugins/gtf/src/GtfAdapter/GtfAdapter.ts b/plugins/gtf/src/GtfAdapter/GtfAdapter.ts
index ab643ea9a4..06be3f4fc4 100644
--- a/plugins/gtf/src/GtfAdapter/GtfAdapter.ts
+++ b/plugins/gtf/src/GtfAdapter/GtfAdapter.ts
@@ -1,6 +1,6 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
import {
+ IntervalTree,
SimpleFeature,
doesIntersect2,
fetchAndMaybeUnzip,
diff --git a/plugins/hic/package.json b/plugins/hic/package.json
index 8ced7dec5a..f817e45c85 100644
--- a/plugins/hic/package.json
+++ b/plugins/hic/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-hic",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 hic adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/plugins/jobs-management/package.json b/plugins/jobs-management/package.json
index af8bec6a54..bbb3790d49 100644
--- a/plugins/jobs-management/package.json
+++ b/plugins/jobs-management/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-jobs-management",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 jobs management",
"keywords": [
"jbrowse",
diff --git a/plugins/legacy-jbrowse/package.json b/plugins/legacy-jbrowse/package.json
index 48eac310db..ca772d93a9 100644
--- a/plugins/legacy-jbrowse/package.json
+++ b/plugins/legacy-jbrowse/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-legacy-jbrowse",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 plugin for connecting to and reading JBrowse 1 data",
"keywords": [
"jbrowse",
diff --git a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/HttpMap.test.ts b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/HttpMap.test.ts
index e5a6f07180..d4b6fb1809 100644
--- a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/HttpMap.test.ts
+++ b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/HttpMap.test.ts
@@ -1,9 +1,9 @@
import path from 'path'
import HttpMap from './HttpMap.ts'
-import first from '../../test_data/names/0.json'
-import last from '../../test_data/names/f.json'
-import meta from '../../test_data/names/meta.json'
+import first from '../../test_data/names/0.json' with { type: 'json' }
+import last from '../../test_data/names/f.json' with { type: 'json' }
+import meta from '../../test_data/names/meta.json' with { type: 'json' }
test('read from meta', async () => {
const rootTemplate = path
diff --git a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts
index 90f78c262e..0264dadcea 100644
--- a/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts
+++ b/plugins/legacy-jbrowse/src/JBrowse1TextSearchAdapter/JBrowse1TextSearchAdapter.test.ts
@@ -4,9 +4,9 @@ import BaseResult from '@jbrowse/core/TextSearch/BaseResults'
import Adapter from './JBrowse1TextSearchAdapter.ts'
import configSchema from './configSchema.ts'
-import first from '../../test_data/names/0.json'
-import last from '../../test_data/names/f.json'
-import meta from '../../test_data/names/meta.json'
+import first from '../../test_data/names/0.json' with { type: 'json' }
+import last from '../../test_data/names/f.json' with { type: 'json' }
+import meta from '../../test_data/names/meta.json' with { type: 'json' }
function mockFetch(url: RequestInfo | URL) {
let response = {}
diff --git a/plugins/linear-comparative-view/package.json b/plugins/linear-comparative-view/package.json
index 9c48dfc9e7..a5d53a0474 100644
--- a/plugins/linear-comparative-view/package.json
+++ b/plugins/linear-comparative-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-linear-comparative-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 linear comparative view",
"keywords": [
"jbrowse",
diff --git a/plugins/linear-genome-view/package.json b/plugins/linear-genome-view/package.json
index c5bb418847..eaef0d2c79 100644
--- a/plugins/linear-genome-view/package.json
+++ b/plugins/linear-genome-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-linear-genome-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 linear genome view",
"keywords": [
"jbrowse",
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/CenterLine.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/CenterLine.tsx
index 0a44590bf4..8a021e1ae0 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/CenterLine.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/CenterLine.tsx
@@ -3,7 +3,7 @@ import { useRef } from 'react'
import { makeStyles } from '@jbrowse/core/util/tss-react'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Gridlines.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Gridlines.tsx
index 1c85b6dce0..27b88e495d 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Gridlines.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Gridlines.tsx
@@ -8,7 +8,7 @@ import {
} from '../../BaseLinearDisplay/components/Block.tsx'
import { makeTicks } from '../util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
index c78c2fb664..e819f0b21f 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
@@ -10,7 +10,7 @@ import OverviewScalebar from './OverviewScalebar.tsx'
import SearchBox from './SearchBox.tsx'
import { HEADER_BAR_HEIGHT } from '../consts.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const useStyles = makeStyles()({
headerBar: {
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx
index f36310c3ae..ec48c3085b 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx
@@ -5,7 +5,7 @@ import { Button, alpha } from '@mui/material'
import { SPACING } from '../consts.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
const useStyles = makeStyles()(theme => ({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx
index b1aeca4fdd..e1111832da 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx
@@ -2,7 +2,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Typography } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const useStyles = makeStyles()({
bp: {
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx
index a5887bbead..d904f0f0eb 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx
@@ -3,7 +3,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { IconButton } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const useStyles = makeStyles()(theme => ({
toggleButton: {
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx
index d358cc26f2..abe075b726 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx
@@ -9,7 +9,7 @@ import ZoomOut from '@mui/icons-material/ZoomOut'
import { IconButton, Slider, Tooltip } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { SliderValueLabelProps } from '@mui/material'
// lazies
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/ImportForm.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/ImportForm.tsx
index d9012ce225..79ba2ecfbd 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/ImportForm.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/ImportForm.tsx
@@ -16,7 +16,7 @@ import { observer } from 'mobx-react'
import ImportFormRefNameAutocomplete from './ImportFormRefNameAutocomplete.tsx'
import { handleSelectedRegion, navToOption } from '../../searchUtils.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type BaseResult from '@jbrowse/core/TextSearch/BaseResults'
const useStyles = makeStyles()(theme => ({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/ImportFormRefNameAutocomplete.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/ImportFormRefNameAutocomplete.tsx
index 5e21f19e25..c4b8100d03 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/ImportFormRefNameAutocomplete.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/ImportFormRefNameAutocomplete.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react'
import RefNameAutocomplete from './RefNameAutocomplete/index.tsx'
import { fetchResults } from './util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type BaseResult from '@jbrowse/core/TextSearch/BaseResults'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.test.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.test.tsx
index 665246e249..c0c84aed9b 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.test.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.test.tsx
@@ -1,5 +1,5 @@
import { createJBrowseTheme } from '@jbrowse/core/ui'
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { ThemeProvider } from '@mui/material'
import { fireEvent, render, waitFor } from '@testing-library/react'
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.tsx
index bfdab2e4ed..2b4578b139 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeView.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react'
import LinearGenomeViewContainer from './LinearGenomeViewContainer.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
// lazies
const ImportForm = lazy(() => import('./ImportForm.tsx'))
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeViewContainer.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeViewContainer.tsx
index b1a44a5054..723d5bd6a9 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeViewContainer.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/LinearGenomeViewContainer.tsx
@@ -9,7 +9,7 @@ import { observer } from 'mobx-react'
import TrackContainer from './TrackContainer.tsx'
import TracksContainer from './TracksContainer.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
// lazies
const NoTracksActiveButton = lazy(() => import('./NoTracksActiveButton.tsx'))
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/MiniControls.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/MiniControls.tsx
index 3ec47d7938..1e11225862 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/MiniControls.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/MiniControls.tsx
@@ -7,7 +7,7 @@ import ZoomOut from '@mui/icons-material/ZoomOut'
import { IconButton, Paper, alpha } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const useStyles = makeStyles()(theme => ({
background: {
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/NoTracksActiveButton.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/NoTracksActiveButton.tsx
index cfd3e84519..d5d41b2a6d 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/NoTracksActiveButton.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/NoTracksActiveButton.tsx
@@ -3,7 +3,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Button, Paper, Typography } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const useStyles = makeStyles()(theme => ({
note: {
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberband.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberband.tsx
index 9f92646988..1d1527cd12 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberband.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberband.tsx
@@ -8,7 +8,7 @@ import OverviewRubberbandHoverTooltip from './OverviewRubberbandHoverTooltip.tsx
import RubberbandSpan from './RubberbandSpan.tsx'
import { getRelativeX } from './util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberbandHoverTooltip.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberbandHoverTooltip.tsx
index 702181bf11..e298bbc098 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberbandHoverTooltip.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewRubberbandHoverTooltip.tsx
@@ -3,7 +3,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Tooltip } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebar.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebar.tsx
index 4a5e6f4181..379b2447da 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebar.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebar.tsx
@@ -15,7 +15,7 @@ import OverviewScalebarTickLabels from './OverviewScalebarTickLabels.tsx'
import { getCytobands } from './util.ts'
import { HEADER_BAR_HEIGHT, HEADER_OVERVIEW_HEIGHT } from '../consts.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarPolygon.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarPolygon.tsx
index ef3499fe8b..942170eb87 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarPolygon.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarPolygon.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react'
import { HEADER_BAR_HEIGHT } from '../consts.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
const OverviewScalebarPolygon = observer(function OverviewScalebarPolygon({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarTickLabels.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarTickLabels.tsx
index c70a783a36..5eb6e350e4 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarTickLabels.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/OverviewScalebarTickLabels.tsx
@@ -3,11 +3,10 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Typography } from '@mui/material'
import { observer } from 'mobx-react'
-// core
import { HEADER_OVERVIEW_HEIGHT } from '../consts.ts'
import { chooseGridPitch } from '../util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Rubberband.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Rubberband.tsx
index 780684db4e..1854976a3e 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Rubberband.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Rubberband.tsx
@@ -8,7 +8,7 @@ import RubberbandSpan from './RubberbandSpan.tsx'
import VerticalGuide from './VerticalGuide.tsx'
import { useRangeSelect } from './useRangeSelect.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.test.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.test.tsx
index 8223436519..1e2986d289 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.test.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.test.tsx
@@ -1,4 +1,4 @@
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+import { createTestSession } from '@jbrowse/web/src/rootModel/index.js'
import { render, waitFor } from '@testing-library/react'
import Scalebar from './Scalebar.tsx'
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.tsx
index 582bcbf25d..d08f3b8078 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Scalebar.tsx
@@ -8,7 +8,7 @@ import Gridlines from './Gridlines.tsx'
import ScalebarCoordinateLabels from './ScalebarCoordinateLabels.tsx'
import ScalebarRefNameLabels from './ScalebarRefNameLabels.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarCoordinateLabels.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarCoordinateLabels.tsx
index d58ad1a2cc..5fa93508c9 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarCoordinateLabels.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarCoordinateLabels.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react'
import { makeTicks } from '../util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarRefNameLabels.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarRefNameLabels.tsx
index e0354395d6..4016900033 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarRefNameLabels.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/ScalebarRefNameLabels.tsx
@@ -4,7 +4,7 @@ import { Menu } from '@jbrowse/core/ui'
import { makeStyles } from '@jbrowse/core/util/tss-react'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackContainer.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackContainer.tsx
index 1cf87f2fe7..a7cc5f6c05 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackContainer.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackContainer.tsx
@@ -12,7 +12,7 @@ import TrackLabelContainer from './TrackLabelContainer.tsx'
import TrackRenderingContainer from './TrackRenderingContainer.tsx'
import { shouldSwapTracks } from './util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
const useStyles = makeStyles()(theme => ({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabel.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabel.tsx
index c1c7460195..7e7d388dc5 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabel.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabel.tsx
@@ -9,7 +9,7 @@ import { observer } from 'mobx-react'
import TrackLabelDragHandle from './TrackLabelDragHandle.tsx'
import TrackLabelMenu from './TrackLabelMenu.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
const useStyles = makeStyles()(theme => ({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelContainer.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelContainer.tsx
index cf4eb3c6c5..66ea5ddb05 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelContainer.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelContainer.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react'
import TrackLabel from './TrackLabel.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
const useStyles = makeStyles()({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelDragHandle.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelDragHandle.tsx
index e0d509bb51..771e6d57a5 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelDragHandle.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackLabelDragHandle.tsx
@@ -1,7 +1,7 @@
import { makeStyles } from '@jbrowse/core/util/tss-react'
import DragIcon from '@mui/icons-material/DragIndicator'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
const useStyles = makeStyles()({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackRenderingContainer.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackRenderingContainer.tsx
index e8f3e6b98f..14b3b91037 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TrackRenderingContainer.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TrackRenderingContainer.tsx
@@ -4,7 +4,7 @@ import { LoadingEllipses } from '@jbrowse/core/ui'
import { makeStyles } from '@jbrowse/core/util/tss-react'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
const useStyles = makeStyles()({
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/TracksContainer.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/TracksContainer.tsx
index b8d92d814f..212e821d87 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/TracksContainer.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/TracksContainer.tsx
@@ -14,7 +14,7 @@ import { useRangeSelect } from './useRangeSelect.ts'
import { useSideScroll } from './useSideScroll.ts'
import { useWheelScroll } from './useWheelScroll.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
const CenterLine = lazy(() => import('./CenterLine.tsx'))
const Highlight = lazy(() => import('./Highlight.tsx'))
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/VerticalGuide.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/VerticalGuide.tsx
index 7f1a719bb3..fc56ee123f 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/VerticalGuide.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/VerticalGuide.tsx
@@ -3,7 +3,7 @@ import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Tooltip } from '@mui/material'
import { observer } from 'mobx-react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/useRangeSelect.ts b/plugins/linear-genome-view/src/LinearGenomeView/components/useRangeSelect.ts
index bb64275c61..43e67b8662 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/useRangeSelect.ts
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/useRangeSelect.ts
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useState } from 'react'
import { getRelativeX } from './util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
interface AnchorPosition {
offsetX: number
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/useSideScroll.ts b/plugins/linear-genome-view/src/LinearGenomeView/components/useSideScroll.ts
index 83314a0dd7..7e88648fb4 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/useSideScroll.ts
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/useSideScroll.ts
@@ -1,7 +1,7 @@
import type React from 'react'
import { useEffect, useRef, useState } from 'react'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
export function useSideScroll(model: LinearGenomeViewModel) {
const [mouseDragging, setMouseDragging] = useState(false)
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/index.test.ts b/plugins/linear-genome-view/src/LinearGenomeView/index.test.ts
index 08c505cea3..77ff2d5eed 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/index.test.ts
+++ b/plugins/linear-genome-view/src/LinearGenomeView/index.test.ts
@@ -11,8 +11,8 @@ import { waitFor } from '@testing-library/react'
import { stateModelFactory } from './index.ts'
import { BaseLinearDisplayComponent } from '../index.ts'
-import hg38Regions from './hg38DisplayedRegions.json'
-import volvoxDisplayedRegions from './volvoxDisplayedRegions.json'
+import hg38Regions from './hg38DisplayedRegions.json' with { type: 'json' }
+import volvoxDisplayedRegions from './volvoxDisplayedRegions.json' with { type: 'json' }
import { stateModelFactory as LinearBasicDisplayStateModelFactory } from '../LinearBareDisplay/index.ts'
import type { LinearGenomeViewModel } from './index.ts'
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGGridlines.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGGridlines.tsx
index f7d11135c6..1bcbc67883 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGGridlines.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGGridlines.tsx
@@ -3,7 +3,7 @@ import { useTheme } from '@mui/material'
import { makeTicks } from '../util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGHeader.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGHeader.tsx
index 9082ff1ff4..c5bcb3d30c 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGHeader.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGHeader.tsx
@@ -8,7 +8,7 @@ import Cytobands from '../components/Cytobands.tsx'
import OverviewScalebarPolygon from '../components/OverviewScalebarPolygon.tsx'
import { HEADER_OVERVIEW_HEIGHT } from '../consts.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
export default function SVGHeader({
model,
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGLinearGenomeView.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGLinearGenomeView.tsx
index 4e24f16c2d..abb3d521d8 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGLinearGenomeView.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGLinearGenomeView.tsx
@@ -18,7 +18,7 @@ import SVGHeader from './SVGHeader.tsx'
import SVGTracks from './SVGTracks.tsx'
import { totalHeight } from './util.ts'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { ExportSvgOptions } from '../types.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRegionSeparators.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRegionSeparators.tsx
index f1ec1a0dec..d0e5e050ca 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRegionSeparators.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRegionSeparators.tsx
@@ -1,4 +1,4 @@
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRuler.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRuler.tsx
index a9058fb170..de10865b66 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRuler.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGRuler.tsx
@@ -4,7 +4,7 @@ import { useTheme } from '@mui/material'
import { makeTicks } from '../util.ts'
import SVGRegionSeparators from './SVGRegionSeparators.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGScalebar.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGScalebar.tsx
index 803e2ffcfa..b780443e34 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGScalebar.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGScalebar.tsx
@@ -1,7 +1,7 @@
import { getBpDisplayStr, stripAlpha } from '@jbrowse/core/util'
import { useTheme } from '@mui/material'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
type LGV = LinearGenomeViewModel
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGTracks.tsx b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGTracks.tsx
index b192310e55..b7766fecfe 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGTracks.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/svgcomponents/SVGTracks.tsx
@@ -4,7 +4,7 @@ import { getTrackName } from '@jbrowse/core/util/tracks'
import SVGRegionSeparators from './SVGRegionSeparators.tsx'
import SVGTrackLabel from './SVGTrackLabel.tsx'
-import type { LinearGenomeViewModel } from '..'
+import type { LinearGenomeViewModel } from '../index.ts'
import type { AnyConfigurationModel } from '@jbrowse/core/configuration'
type LGV = LinearGenomeViewModel
diff --git a/plugins/lollipop/package.json b/plugins/lollipop/package.json
index 27cb9a89f1..75b3fb54a3 100644
--- a/plugins/lollipop/package.json
+++ b/plugins/lollipop/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-lollipop",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 plugin for lollipops",
"keywords": [
"jbrowse",
diff --git a/plugins/menus/package.json b/plugins/menus/package.json
index 9b849bd063..2f59009866 100644
--- a/plugins/menus/package.json
+++ b/plugins/menus/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-menus",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 basic menus",
"keywords": [
"jbrowse",
diff --git a/plugins/rdf/package.json b/plugins/rdf/package.json
index 5531b056c3..1c018310a0 100644
--- a/plugins/rdf/package.json
+++ b/plugins/rdf/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-rdf",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 RDF resources",
"keywords": [
"jbrowse",
diff --git a/plugins/rdf/src/SPARQLAdapter/SPARQLAdapter.test.ts b/plugins/rdf/src/SPARQLAdapter/SPARQLAdapter.test.ts
index 38e7cccb2c..2312763ea4 100644
--- a/plugins/rdf/src/SPARQLAdapter/SPARQLAdapter.test.ts
+++ b/plugins/rdf/src/SPARQLAdapter/SPARQLAdapter.test.ts
@@ -3,9 +3,9 @@ import { toArray } from 'rxjs/operators'
import Adapter from './SPARQLAdapter.ts'
import configSchema from './configSchema.ts'
-import emptyQueryResponse from './test_data/emptyQueryResponse.json'
-import queryResponse from './test_data/queryResponse.json'
-import refNamesResponse from './test_data/refNamesResponse.json'
+import emptyQueryResponse from './test_data/emptyQueryResponse.json' with { type: 'json' }
+import queryResponse from './test_data/queryResponse.json' with { type: 'json' }
+import refNamesResponse from './test_data/refNamesResponse.json' with { type: 'json' }
// window.fetch = jest.fn(url => new Promise(resolve => resolve()))
diff --git a/plugins/sequence/package.json b/plugins/sequence/package.json
index f70943cfad..6b53e28f3c 100644
--- a/plugins/sequence/package.json
+++ b/plugins/sequence/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-sequence",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 sequence adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/plugins/spreadsheet-view/package.json b/plugins/spreadsheet-view/package.json
index ddc56bb7e2..5bdfa15fec 100644
--- a/plugins/spreadsheet-view/package.json
+++ b/plugins/spreadsheet-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-spreadsheet-view",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 spreadsheet view",
"keywords": [
"jbrowse",
diff --git a/plugins/sv-inspector/package.json b/plugins/sv-inspector/package.json
index a10185726c..ca8a868a58 100644
--- a/plugins/sv-inspector/package.json
+++ b/plugins/sv-inspector/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-sv-inspector",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 SV inspector view",
"keywords": [
"jbrowse",
diff --git a/plugins/text-indexing/package.json b/plugins/text-indexing/package.json
index 6f43c84d17..47be3b58a2 100644
--- a/plugins/text-indexing/package.json
+++ b/plugins/text-indexing/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-text-indexing",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 text indexing rpc method",
"keywords": [
"jbrowse",
diff --git a/plugins/trix/package.json b/plugins/trix/package.json
index e531f52e72..781e89e7ac 100644
--- a/plugins/trix/package.json
+++ b/plugins/trix/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-trix",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 trix text search adapter",
"keywords": [
"jbrowse",
@@ -32,7 +33,7 @@
"react": ">=18.0.0"
},
"dependencies": {
- "@gmod/trix": "^3.0.5",
+ "@gmod/trix": "^3.0.9",
"@jbrowse/core": "workspace:^"
},
"publishConfig": {
diff --git a/plugins/variants/package.json b/plugins/variants/package.json
index 276998555d..fd21d4a56e 100644
--- a/plugins/variants/package.json
+++ b/plugins/variants/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-variants",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 variant adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/plugins/variants/src/VcfAdapter/VcfAdapter.ts b/plugins/variants/src/VcfAdapter/VcfAdapter.ts
index 31f77fc2a4..3c9cf85e94 100644
--- a/plugins/variants/src/VcfAdapter/VcfAdapter.ts
+++ b/plugins/variants/src/VcfAdapter/VcfAdapter.ts
@@ -1,7 +1,6 @@
-import { IntervalTree } from '@flatten-js/interval-tree'
import VcfParser from '@gmod/vcf'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
-import { fetchAndMaybeUnzip } from '@jbrowse/core/util'
+import { IntervalTree, fetchAndMaybeUnzip } from '@jbrowse/core/util'
import { openLocation } from '@jbrowse/core/util/io'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
diff --git a/plugins/wiggle/package.json b/plugins/wiggle/package.json
index 833964fb0f..c25cbd3161 100644
--- a/plugins/wiggle/package.json
+++ b/plugins/wiggle/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/plugin-wiggle",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 wiggle adapters, tracks, etc.",
"keywords": [
"jbrowse",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c28fb0c725..33e4469a44 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -209,9 +209,6 @@ importers:
electron-builder:
specifier: ^25.1.8
version: 25.1.8(electron-builder-squirrel-windows@25.1.8)
- electron-mock-ipc:
- specifier: ^0.3.14
- version: 0.3.14(electron@40.0.0)
eslint:
specifier: ^9.39.2
version: 9.39.2
@@ -437,9 +434,6 @@ importers:
canvas2svg:
specifier: ^1.0.16
version: 1.0.16
- colord:
- specifier: ^2.9.3
- version: 2.9.3
copy-to-clipboard:
specifier: ^3.3.3
version: 3.3.3
@@ -470,9 +464,6 @@ importers:
librpc-web-mod:
specifier: ^2.1.1
version: 2.1.1
- load-script:
- specifier: ^2.0.0
- version: 2.0.0
mobx:
specifier: ^6.15.0
version: 6.15.0
@@ -765,8 +756,8 @@ importers:
specifier: ^8.1.1
version: 8.1.1
'@gmod/bed':
- specifier: ^2.1.7
- version: 2.1.7
+ specifier: ^2.1.10
+ version: 2.1.10
'@gmod/tabix':
specifier: ^3.2.2
version: 3.2.2
@@ -1539,8 +1530,8 @@ importers:
plugins/trix:
dependencies:
'@gmod/trix':
- specifier: ^3.0.5
- version: 3.0.5
+ specifier: ^3.0.9
+ version: 3.0.9
'@jbrowse/core':
specifier: workspace:^
version: link:../../packages/core
@@ -1885,8 +1876,8 @@ importers:
specifier: ^4.35.5
version: 4.35.5
cross-env:
- specifier: ^7.0.3
- version: 7.0.3
+ specifier: ^10.1.0
+ version: 10.1.0
electron:
specifier: 40.0.0
version: 40.0.0
@@ -1894,8 +1885,8 @@ importers:
specifier: ^40.0.0
version: 40.0.0
selenium-webdriver:
- specifier: ^4.39.0
- version: 4.39.0
+ specifier: ^4.40.0
+ version: 4.40.0
products/jbrowse-img:
dependencies:
@@ -3223,6 +3214,9 @@ packages:
'@emotion/weak-memoize@0.4.0':
resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
+ '@epic-web/invariant@1.0.0':
+ resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
+
'@esbuild/aix-ppc64@0.27.2':
resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
engines: {node: '>=18'}
@@ -3459,8 +3453,8 @@ packages:
resolution: {integrity: sha512-Vpz/ezTAUslIsKCEvsA0zPHkobrwMCUw7E+hvAwsBP8H1BiD67Scak5hX8cJI7Sv4NRgKB/Zjvq0XfVa/wZ6KQ==}
engines: {node: '>=6'}
- '@gmod/bed@2.1.7':
- resolution: {integrity: sha512-ddxGWgcbI984gTdsIPbrFpM2h7s7kNWWKmxD+xKtv5N+Pe4RaoPdJ6nAc33QFkUjuM2s+3QIf81qjFLDVGhLsA==}
+ '@gmod/bed@2.1.10':
+ resolution: {integrity: sha512-begb47SbolFRLXUaQA8w1yBdzPFEw+FncHvfLMxfDC0nacDeU3N72BUPhK4Dq51mi8QpN4NfT3dR8O2j2g1Lww==}
engines: {node: '>=6'}
'@gmod/bgzf-filehandle@6.0.10':
@@ -3493,8 +3487,8 @@ packages:
resolution: {integrity: sha512-lQQCuanjsnVNzH9n21LTMGykvRbpLbEQk3AL+aKnjf72gfV07mLZ116gtvDFu5huxbxWialOHGGC7iJAQDEi5Q==}
engines: {node: '>=6'}
- '@gmod/trix@3.0.5':
- resolution: {integrity: sha512-/v8Sn9OUT5UYlhNW3GE4wedxo8gHn1Zgs9DYRwjpjsetNgFtWrEZwjTHaAkTE6HDuYd5qtEyT1C0leD3ljURoQ==}
+ '@gmod/trix@3.0.9':
+ resolution: {integrity: sha512-fOVWXVRKt+51tHo9QBk7kpwYqsoDOqtvtw/Mio+FX4JGxV6rVduCpljtSwd2sYe8GyCpmUFOJtWQMAVXdqHsHw==}
engines: {node: '>=10'}
'@gmod/twobit@6.0.1':
@@ -5540,9 +5534,9 @@ packages:
create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
- cross-env@7.0.3:
- resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
- engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
+ cross-env@10.1.0:
+ resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==}
+ engines: {node: '>=20'}
hasBin: true
cross-fetch@3.2.0:
@@ -5954,11 +5948,6 @@ packages:
electron-localshortcut@3.2.1:
resolution: {integrity: sha512-DWvhKv36GsdXKnaFFhEiK8kZZA+24/yFLgtTwJJHc7AFgDjNRIBJZ/jq62Y/dWv9E4ypYwrVWN2bVrCYw1uv7Q==}
- electron-mock-ipc@0.3.14:
- resolution: {integrity: sha512-DouQtwlfk/lDfMQXo7ltefMoJ5t6FTUTfTh99zEJNYok+SlUMzbOFMW5cBzem20NOJ2aAD4Lrc/26CuXCWCTdw==}
- peerDependencies:
- electron: '>=6.0.0'
-
electron-publish@25.1.7:
resolution: {integrity: sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==}
@@ -7430,9 +7419,6 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- load-script@2.0.0:
- resolution: {integrity: sha512-km6cyoPW4rM22JMGb+SHUKPMZVDpUaMpMAKrv8UHWllIxc/qjgMGHD91nY+5hM+/NFs310OZ2pqQeJKs7HqWPA==}
-
loader-runner@4.3.1:
resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==}
engines: {node: '>=6.11.5'}
@@ -8553,8 +8539,8 @@ packages:
select-hose@2.0.0:
resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==}
- selenium-webdriver@4.39.0:
- resolution: {integrity: sha512-NAs9jCU+UeZ/ZmRb8R6zOp7N8eMklefdBYASnaRmCNXdgFE8w3OCxxZmLixkwqnGDHY5VF7hCulfw1Mls43N/A==}
+ selenium-webdriver@4.40.0:
+ resolution: {integrity: sha512-dU0QbnVKdPmoNP8OtMCazRdtU2Ux6Wl4FEpG1iwUbDeajJK1dBAywBLrC1D7YFRtogHzN96AbXBgBAJaarcysw==}
engines: {node: '>= 20.0.0'}
selfsigned@5.5.0:
@@ -10676,6 +10662,8 @@ snapshots:
'@emotion/weak-memoize@0.4.0': {}
+ '@epic-web/invariant@1.0.0': {}
+
'@esbuild/aix-ppc64@0.27.2':
optional: true
@@ -10852,7 +10840,7 @@ snapshots:
pako-esm2: 2.0.2
rxjs: 7.8.2
- '@gmod/bed@2.1.7': {}
+ '@gmod/bed@2.1.10': {}
'@gmod/bgzf-filehandle@6.0.10':
dependencies:
@@ -10894,7 +10882,7 @@ snapshots:
'@jbrowse/quick-lru': 7.3.5
generic-filehandle2: 2.0.18
- '@gmod/trix@3.0.5': {}
+ '@gmod/trix@3.0.9': {}
'@gmod/twobit@6.0.1':
dependencies:
@@ -13375,8 +13363,9 @@ snapshots:
create-require@1.1.1:
optional: true
- cross-env@7.0.3:
+ cross-env@10.1.0:
dependencies:
+ '@epic-web/invariant': 1.0.0
cross-spawn: 7.0.6
cross-fetch@3.2.0(encoding@0.1.13):
@@ -13830,10 +13819,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- electron-mock-ipc@0.3.14(electron@40.0.0):
- dependencies:
- electron: 40.0.0
-
electron-publish@25.1.7:
dependencies:
'@types/fs-extra': 9.0.13
@@ -15793,8 +15778,6 @@ snapshots:
lines-and-columns@1.2.4: {}
- load-script@2.0.0: {}
-
loader-runner@4.3.1: {}
locate-path@5.0.0:
@@ -16958,7 +16941,7 @@ snapshots:
select-hose@2.0.0: {}
- selenium-webdriver@4.39.0:
+ selenium-webdriver@4.40.0:
dependencies:
'@bazel/runfiles': 6.5.0
jszip: 3.10.1
diff --git a/products/jbrowse-cli/bin/run b/products/jbrowse-cli/bin/run
index b0d3354421..7071b2e935 100755
--- a/products/jbrowse-cli/bin/run
+++ b/products/jbrowse-cli/bin/run
@@ -1,3 +1,4 @@
#!/usr/bin/env node
-require('../dist/index.js').main(process.argv.slice(2))
+import { main } from '../dist/index.js'
+main(process.argv.slice(2))
diff --git a/products/jbrowse-cli/package.json b/products/jbrowse-cli/package.json
index 31126a182f..cb54baa77a 100644
--- a/products/jbrowse-cli/package.json
+++ b/products/jbrowse-cli/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/cli",
"version": "4.0.4",
+ "type": "module",
"description": "A command line tool for working with JBrowse 2",
"keywords": [
"jbrowse",
@@ -29,7 +30,7 @@
},
"scripts": {
"prebuild": "pnpm clean",
- "build": "tsc && webpack",
+ "build": "tsc && webpack -c webpack.config.mjs",
"clean": "rimraf bundle",
"prepack": "pnpm clean && pnpm build && pnpm generate-readme",
"generate-readme": "./generate_readme.sh > README.md"
diff --git a/products/jbrowse-cli/src/utils.ts b/products/jbrowse-cli/src/utils.ts
index 19a8d2cb4e..fa36d1975c 100644
--- a/products/jbrowse-cli/src/utils.ts
+++ b/products/jbrowse-cli/src/utils.ts
@@ -198,7 +198,7 @@ function wrapText(text: string, width: number, indent: string) {
}
}
}
- return lines.join('\n' + indent)
+ return lines.join(`\n${indent}`)
}
export function printHelp({
diff --git a/products/jbrowse-cli/tsconfig.json b/products/jbrowse-cli/tsconfig.json
index a7f3dea983..6d741bd82d 100644
--- a/products/jbrowse-cli/tsconfig.json
+++ b/products/jbrowse-cli/tsconfig.json
@@ -1,6 +1,5 @@
{
"compilerOptions": {
- "module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"strict": true,
diff --git a/products/jbrowse-cli/webpack.config.js b/products/jbrowse-cli/webpack.config.mjs
similarity index 80%
rename from products/jbrowse-cli/webpack.config.js
rename to products/jbrowse-cli/webpack.config.mjs
index 1065a6efd7..c627a79a58 100644
--- a/products/jbrowse-cli/webpack.config.js
+++ b/products/jbrowse-cli/webpack.config.mjs
@@ -1,7 +1,11 @@
-const path = require('path')
-const webpack = require('webpack')
+import path from 'path'
+import { fileURLToPath } from 'url'
-module.exports = {
+import webpack from 'webpack'
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+
+export default {
mode: 'development',
entry: './src/bin.ts',
target: 'node',
diff --git a/products/jbrowse-desktop/package.json b/products/jbrowse-desktop/package.json
index b6554bb528..6e51cd7597 100644
--- a/products/jbrowse-desktop/package.json
+++ b/products/jbrowse-desktop/package.json
@@ -105,10 +105,10 @@
},
"devDependencies": {
"@types/selenium-webdriver": "^4.35.5",
- "cross-env": "^7.0.3",
+ "cross-env": "^10.1.0",
"electron": "40.0.0",
"electron-chromedriver": "^40.0.0",
- "selenium-webdriver": "^4.39.0"
+ "selenium-webdriver": "^4.40.0"
},
"browserslist": [
"last 1 chrome version"
diff --git a/products/jbrowse-desktop/src/components/JBrowse.test.tsx b/products/jbrowse-desktop/src/components/JBrowse.test.tsx
deleted file mode 100644
index 0b8ff5b96c..0000000000
--- a/products/jbrowse-desktop/src/components/JBrowse.test.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react'
-
-// must import first to create window.require as side effect
-
-import PluginManager from '@jbrowse/core/PluginManager'
-import { fireEvent, render } from '@testing-library/react'
-
-// locals
-import JBrowse from './JBrowse.tsx'
-import {
- ipcMain,
- ipcRenderer,
-} from '../../../../packages/__mocks__/electron.ts'
-import configSnapshot from '../../test_data/volvox/config.json'
-import corePlugins from '../corePlugins.ts'
-import JBrowseRootModelFactory from '../rootModel/rootModel.ts'
-import sessionModelFactory from '../sessionModel/sessionModel.ts'
-
-import type { SnapshotIn } from '@jbrowse/mobx-state-tree'
-
-jest.mock('../makeWorkerInstance', () => () => {})
-
-type JBrowseRootModel = ReturnType
-
-function getPluginManager(initialState?: SnapshotIn) {
- const pluginManager = new PluginManager(
- corePlugins.map(P => new P()),
- ).createPluggableElements()
-
- const rootModel = JBrowseRootModelFactory({
- pluginManager,
- sessionModelFactory,
- }).create(
- {
- jbrowse: initialState || {
- ...configSnapshot,
- configuration: {
- rpc: {
- defaultDriver: 'MainThreadRpcDriver',
- },
- },
- },
- },
- { pluginManager },
- )
- return pluginManager.setRootModel(rootModel).configure()
-}
-
-test('basic test of electron-mock-ipc', () => {
- const testMessage = 'test'
- ipcMain.once('test-event', (_ev: unknown, obj: string) => {
- expect(obj).toEqual(testMessage)
- })
-
- ipcRenderer.send('test-event', testMessage)
-})
-
-xit('renders start screen', async () => {
- ipcMain.handle('listSessions', () => ({}))
-
- const { findByText } = render()
- fireEvent.click(await findByText('Empty'))
- await findByText('Help')
-})
diff --git a/products/jbrowse-desktop/src/components/StartScreen/Logo.tsx b/products/jbrowse-desktop/src/components/StartScreen/Logo.tsx
index 23168ae2f9..4bee74d3ac 100644
--- a/products/jbrowse-desktop/src/components/StartScreen/Logo.tsx
+++ b/products/jbrowse-desktop/src/components/StartScreen/Logo.tsx
@@ -2,7 +2,7 @@ import { LogoFull } from '@jbrowse/core/ui/Logo'
import { makeStyles } from '@jbrowse/core/util/tss-react'
import { Typography } from '@mui/material'
-import packageJSON from '../../../package.json'
+import packageJSON from '../../../package.json' with { type: 'json' }
const useStyles = makeStyles()({
logo: {
diff --git a/products/jbrowse-desktop/src/rootModel/__snapshots__/rootModel.test.ts.snap b/products/jbrowse-desktop/src/rootModel/__snapshots__/rootModel.test.ts.snap
deleted file mode 100644
index 322995ad78..0000000000
--- a/products/jbrowse-desktop/src/rootModel/__snapshots__/rootModel.test.ts.snap
+++ /dev/null
@@ -1,421 +0,0 @@
-// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
-
-exports[`adds menus 1`] = `
-[
- {
- "label": "File",
- "menuItems": [
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Open session...",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Save session as...",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": [Function],
- "label": "Open assembly...",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Open track...",
- "onClick": [Function],
- },
- {
- "icon": [Function],
- "label": "Open connection...",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Return to start screen",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Exit",
- "onClick": [Function],
- },
- ],
- },
- {
- "label": "Add",
- "menuItems": [],
- },
- {
- "label": "Tools",
- "menuItems": [
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Undo",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Redo",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Plugin store",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Preferences",
- "onClick": [Function],
- },
- {
- "icon": [Function],
- "label": "Open assembly manager",
- "onClick": [Function],
- },
- {
- "checked": false,
- "helpText": "Workspaces allow you to organize views into tabs and tiles. You can drag views between tabs or split them side-by-side.",
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Use workspaces",
- "onClick": [Function],
- "type": "checkbox",
- },
- ],
- },
-]
-`;
-
-exports[`adds menus 2`] = `
-[
- {
- "label": "File",
- "menuItems": [
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Open session...",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Save session as...",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": [Function],
- "label": "Open assembly...",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Open track...",
- "onClick": [Function],
- },
- {
- "icon": [Function],
- "label": "Open connection...",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Return to start screen",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Exit",
- "onClick": [Function],
- },
- ],
- },
- {
- "label": "Add",
- "menuItems": [],
- },
- {
- "label": "Tools",
- "menuItems": [
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Undo",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Redo",
- "onClick": [Function],
- },
- {
- "type": "divider",
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Plugin store",
- "onClick": [Function],
- },
- {
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Preferences",
- "onClick": [Function],
- },
- {
- "icon": [Function],
- "label": "Open assembly manager",
- "onClick": [Function],
- },
- {
- "checked": false,
- "helpText": "Workspaces allow you to organize views into tabs and tiles. You can drag views between tabs or split them side-by-side.",
- "icon": {
- "$$typeof": Symbol(react.memo),
- "compare": null,
- "type": {
- "$$typeof": Symbol(react.forward_ref),
- "render": [Function],
- },
- },
- "label": "Use workspaces",
- "onClick": [Function],
- "type": "checkbox",
- },
- ],
- },
- {
- "label": "Second Menu",
- "menuItems": [
- {
- "label": "First Menu Item",
- "onClick": [Function],
- },
- {
- "label": "Second Menu Item",
- "onClick": [Function],
- },
- {
- "label": "First Sub Menu",
- "subMenu": [
- {
- "label": "First Sub Menu Item",
- "onClick": [Function],
- },
- {
- "label": "Second Sub Menu Item",
- "onClick": [Function],
- },
- ],
- },
- ],
- },
- {
- "label": "Third Menu",
- "menuItems": [],
- },
-]
-`;
-
-exports[`adds track and connection configs to an assembly 1`] = `
-{
- "aliases": [
- "assemblyA",
- ],
- "name": "assembly1",
- "sequence": {
- "adapter": {
- "adapterId": "sequenceConfigAdapterId",
- "features": [
- {
- "end": 10,
- "refName": "ctgA",
- "seq": "cattgttgcg",
- "start": 0,
- "uniqueId": "firstId",
- },
- ],
- "type": "FromConfigSequenceAdapter",
- },
- "displays": [
- {
- "displayId": "sequenceConfigId-LinearReferenceSequenceDisplay",
- "type": "LinearReferenceSequenceDisplay",
- },
- {
- "displayId": "sequenceConfigId-LinearGCContentDisplay",
- "type": "LinearGCContentDisplay",
- },
- ],
- "trackId": "sequenceConfigId",
- "type": "ReferenceSequenceTrack",
- },
-}
-`;
-
-exports[`adds track and connection configs to an assembly 2`] = `
-{
- "trackId": "trackId0",
- "type": "FeatureTrack",
-}
-`;
-
-exports[`adds track and connection configs to an assembly 3`] = `
-{
- "connectionId": "connectionId0",
- "dataDirLocation": {
- "internetAccountId": undefined,
- "internetAccountPreAuthorization": undefined,
- "locationType": "UriLocation",
- "uri": "http://mysite.com/jbrowse/data/",
- },
- "type": "JBrowse1Connection",
-}
-`;
-
-exports[`creates with defaults 1`] = `{}`;
diff --git a/products/jbrowse-desktop/src/rootModel/rootModel.test.ts b/products/jbrowse-desktop/src/rootModel/rootModel.test.ts
deleted file mode 100644
index 0d985d9d98..0000000000
--- a/products/jbrowse-desktop/src/rootModel/rootModel.test.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-// import electron first, important, because the electron mock creates
-// window.require
-import 'electron'
-
-// we use mainthread rpc so we mock the makeWorkerInstance to an empty file
-import PluginManager from '@jbrowse/core/PluginManager'
-import { getSnapshot } from '@jbrowse/mobx-state-tree'
-
-import corePlugins from '../corePlugins.ts'
-import rootModelFactory from './rootModel.ts'
-import sessionModelFactory from '../sessionModel/sessionModel.ts'
-
-jest.mock('../makeWorkerInstance', () => () => {})
-
-function getRootModel() {
- const pluginManager = new PluginManager(corePlugins.map(P => new P()))
- pluginManager.createPluggableElements()
- pluginManager.configure()
- return rootModelFactory({
- pluginManager,
- sessionModelFactory,
- })
-}
-afterEach(() => {
- localStorage.clear()
- sessionStorage.clear()
-})
-
-const mainThreadConfig = {
- jbrowse: {
- configuration: {
- rpc: {
- defaultDriver: 'MainThreadRpcDriver',
- },
- },
- },
-}
-
-test('creates with defaults', () => {
- const root = getRootModel().create(mainThreadConfig)
- expect(root.session).toBeUndefined()
- root.setDefaultSession()
- expect(root.session).toBeTruthy()
- expect(root.jbrowse.assemblies.length).toBe(0)
- expect(getSnapshot(root.jbrowse.configuration)).toMatchSnapshot()
-})
-
-test('creates with a minimal session', () => {
- const root = getRootModel().create({
- ...mainThreadConfig,
- session: {
- name: 'testSession',
- },
- })
- expect(root.session).toBeTruthy()
-})
-
-test('activates a session snapshot', () => {
- const session = { name: 'testSession' }
- localStorage.setItem('localSaved-123', JSON.stringify({ session }))
- Storage.prototype.getItem = jest.fn(
- () => `{"session": {"name": "testSession"}}`,
- )
-
- const root = getRootModel().create(mainThreadConfig)
- expect(root.session).toBeUndefined()
- root.setSession(session)
- expect(root.session).toBeTruthy()
-})
-
-test('adds track and connection configs to an assembly', () => {
- const root = getRootModel().create({
- jbrowse: {
- ...mainThreadConfig.jbrowse,
- assemblies: [
- {
- name: 'assembly1',
- aliases: ['assemblyA'],
- sequence: {
- trackId: 'sequenceConfigId',
- type: 'ReferenceSequenceTrack',
- adapter: {
- type: 'FromConfigSequenceAdapter',
- adapterId: 'sequenceConfigAdapterId',
- features: [
- {
- refName: 'ctgA',
- uniqueId: 'firstId',
- start: 0,
- end: 10,
- seq: 'cattgttgcg',
- },
- ],
- },
- },
- },
- ],
- },
- })
- expect(root.jbrowse.assemblies.length).toBe(1)
- expect(getSnapshot(root.jbrowse.assemblies[0])).toMatchSnapshot()
- const newTrackConf = root.jbrowse.addTrackConf({
- type: 'FeatureTrack',
- trackId: 'trackId0',
- })
- expect(newTrackConf).toMatchSnapshot()
- expect(root.jbrowse.tracks.length).toBe(1)
- const newConnectionConf = root.jbrowse.addConnectionConf({
- type: 'JBrowse1Connection',
- connectionId: 'connectionId0',
- })
- expect(getSnapshot(newConnectionConf)).toMatchSnapshot()
- expect(root.jbrowse.connections.length).toBe(1)
-})
-
-test('throws if session is invalid', () => {
- expect(() => {
- getRootModel().create({
- ...mainThreadConfig,
- session: {},
- })
- }).toThrow()
-})
-
-test('throws if session snapshot is invalid', () => {
- const root = getRootModel().create(mainThreadConfig)
- expect(() => {
- root.setSession({})
- }).toThrow()
-})
-
-test('adds menus', () => {
- const root = getRootModel().create(mainThreadConfig)
- expect(root.menus()).toMatchSnapshot()
- root.appendMenu('Third Menu')
- root.insertMenu('Second Menu', -1)
- root.appendToMenu('Second Menu', {
- label: 'Second Menu Item',
- onClick: () => {},
- })
- root.insertInMenu(
- 'Second Menu',
- {
- label: 'First Menu Item',
- onClick: () => {},
- },
- -1,
- )
- root.appendToSubMenu(['Second Menu', 'First Sub Menu'], {
- label: 'Second Sub Menu Item',
- onClick: () => {},
- })
- root.insertInSubMenu(
- ['Second Menu', 'First Sub Menu'],
- {
- label: 'First Sub Menu Item',
- onClick: () => {},
- },
- -1,
- )
- expect(root.menus()).toMatchSnapshot()
-})
diff --git a/products/jbrowse-desktop/src/rootModel/rootModel.ts b/products/jbrowse-desktop/src/rootModel/rootModel.ts
index b4cba9041f..b5b10d1f5d 100644
--- a/products/jbrowse-desktop/src/rootModel/rootModel.ts
+++ b/products/jbrowse-desktop/src/rootModel/rootModel.ts
@@ -26,7 +26,7 @@ import StorageIcon from '@mui/icons-material/Storage'
import UndoIcon from '@mui/icons-material/Undo'
import { DesktopSessionManagementMixin, getSaveSession } from './Sessions.ts'
-import packageJSON from '../../package.json'
+import packageJSON from '../../package.json' with { type: 'json' }
import OpenSequenceDialog from '../components/OpenSequenceDialog.tsx'
import jobsModelFactory from '../indexJobsModel.ts'
import JBrowseDesktop from '../jbrowseModel.ts'
diff --git a/products/jbrowse-react-linear-genome-view/.storybook/main.js b/products/jbrowse-react-app/.storybook/main.mjs
similarity index 88%
rename from products/jbrowse-react-linear-genome-view/.storybook/main.js
rename to products/jbrowse-react-app/.storybook/main.mjs
index 627b476745..1c5f4053a2 100644
--- a/products/jbrowse-react-linear-genome-view/.storybook/main.js
+++ b/products/jbrowse-react-app/.storybook/main.mjs
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
@@ -15,7 +15,7 @@ module.exports = {
test: /\.(ts|tsx|js|jsx)$/,
use: [
{
- loader: require.resolve('babel-loader'),
+ loader: 'babel-loader',
options: {
rootMode: 'upward',
},
diff --git a/products/jbrowse-react-app/.storybook/middleware.js b/products/jbrowse-react-app/.storybook/middleware.mjs
similarity index 66%
rename from products/jbrowse-react-app/.storybook/middleware.js
rename to products/jbrowse-react-app/.storybook/middleware.mjs
index 6640c0f2ff..e0738ac898 100644
--- a/products/jbrowse-react-app/.storybook/middleware.js
+++ b/products/jbrowse-react-app/.storybook/middleware.mjs
@@ -1,7 +1,7 @@
-const serveStatic = require('serve-static')
+import serveStatic from 'serve-static'
// the default static file serving fails on vcf files due to Content-Encoding
const expressMiddleWare = router => {
router.use(serveStatic('public'))
}
-module.exports = expressMiddleWare
+export default expressMiddleWare
diff --git a/products/jbrowse-react-app/package.json b/products/jbrowse-react-app/package.json
index 96119c9df8..5b8f648f9c 100644
--- a/products/jbrowse-react-app/package.json
+++ b/products/jbrowse-react-app/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/react-app2",
"version": "4.0.3",
+ "type": "module",
"description": "JBrowse 2 app React component",
"keywords": [
"jbrowse",
@@ -33,7 +34,7 @@
"build": "pnpm run /^build:/",
"prepublishOnly": "node output-version.js > src/version.ts && git add -A src && git commit -m '[skip ci] Bump version.ts'",
"build:esm": "tsc --build tsconfig.build.esm.json",
- "build:webpack": "webpack",
+ "build:webpack": "webpack -c webpack.config.mjs",
"clean": "rimraf esm *.tsbuildinfo",
"storybook": "storybook dev --port 6006",
"storybook:build": "storybook build",
diff --git a/products/jbrowse-react-app/stories/examples/WithImportConfigJson.tsx b/products/jbrowse-react-app/stories/examples/WithImportConfigJson.tsx
index a4168b9951..e3680df81d 100644
--- a/products/jbrowse-react-app/stories/examples/WithImportConfigJson.tsx
+++ b/products/jbrowse-react-app/stories/examples/WithImportConfigJson.tsx
@@ -1,7 +1,7 @@
// replace with this in your code:
// import {createViewState,JBrowseApp} from '@jbrowse/react-app2'
import { addRelativeUris } from './util.ts'
-import config from '../../public/test_data/volvox/config.json'
+import config from '../../public/test_data/volvox/config.json' with { type: 'json' }
import { JBrowseApp, createViewState } from '../../src/index.ts'
const configPath = 'test_data/volvox/config.json'
diff --git a/products/jbrowse-react-app/stories/examples/WithWebWorker.tsx b/products/jbrowse-react-app/stories/examples/WithWebWorker.tsx
index 1e8c74777e..5ff4dc07ae 100644
--- a/products/jbrowse-react-app/stories/examples/WithWebWorker.tsx
+++ b/products/jbrowse-react-app/stories/examples/WithWebWorker.tsx
@@ -1,6 +1,6 @@
// replace with this in your code:
// import {createViewState,JBrowseApp} from '@jbrowse/react-app2'
-import volvoxConfig from '../../public/test_data/volvox/config.json'
+import volvoxConfig from '../../public/test_data/volvox/config.json' with { type: 'json' }
import { JBrowseApp, createViewState } from '../../src/index.ts'
// replace with this in your code:
// import makeWorkerInstance from '@jbrowse/react-app2/esm/makeWorkerInstance'
diff --git a/products/jbrowse-react-app/webpack.config.js b/products/jbrowse-react-app/webpack.config.mjs
similarity index 91%
rename from products/jbrowse-react-app/webpack.config.js
rename to products/jbrowse-react-app/webpack.config.mjs
index 1416cd94d8..bc7a604f4c 100644
--- a/products/jbrowse-react-app/webpack.config.js
+++ b/products/jbrowse-react-app/webpack.config.mjs
@@ -1,7 +1,8 @@
-const path = require('path')
-const webpack = require('webpack')
+import path from 'path'
-module.exports = {
+import webpack from 'webpack'
+
+export default {
mode: process.env.NODE_ENV || 'production',
entry: './src/webpack.ts',
devtool: 'source-map',
diff --git a/products/jbrowse-react-app/.storybook/main.js b/products/jbrowse-react-circular-genome-view/.storybook/main.mjs
similarity index 88%
rename from products/jbrowse-react-app/.storybook/main.js
rename to products/jbrowse-react-circular-genome-view/.storybook/main.mjs
index 627b476745..1c5f4053a2 100644
--- a/products/jbrowse-react-app/.storybook/main.js
+++ b/products/jbrowse-react-circular-genome-view/.storybook/main.mjs
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
@@ -15,7 +15,7 @@ module.exports = {
test: /\.(ts|tsx|js|jsx)$/,
use: [
{
- loader: require.resolve('babel-loader'),
+ loader: 'babel-loader',
options: {
rootMode: 'upward',
},
diff --git a/products/jbrowse-react-circular-genome-view/.storybook/middleware.js b/products/jbrowse-react-circular-genome-view/.storybook/middleware.mjs
similarity index 66%
rename from products/jbrowse-react-circular-genome-view/.storybook/middleware.js
rename to products/jbrowse-react-circular-genome-view/.storybook/middleware.mjs
index 6640c0f2ff..e0738ac898 100644
--- a/products/jbrowse-react-circular-genome-view/.storybook/middleware.js
+++ b/products/jbrowse-react-circular-genome-view/.storybook/middleware.mjs
@@ -1,7 +1,7 @@
-const serveStatic = require('serve-static')
+import serveStatic from 'serve-static'
// the default static file serving fails on vcf files due to Content-Encoding
const expressMiddleWare = router => {
router.use(serveStatic('public'))
}
-module.exports = expressMiddleWare
+export default expressMiddleWare
diff --git a/products/jbrowse-react-circular-genome-view/package.json b/products/jbrowse-react-circular-genome-view/package.json
index 172eba818a..c8e8ed442e 100644
--- a/products/jbrowse-react-circular-genome-view/package.json
+++ b/products/jbrowse-react-circular-genome-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/react-circular-genome-view2",
"version": "4.0.4",
+ "type": "module",
"description": "JBrowse 2 circular genome view React component",
"keywords": [
"jbrowse",
@@ -29,7 +30,7 @@
"prepublishOnly": "node output-version.js > src/version.ts && git add -A src && git commit -m '[skip ci] Bump version.ts'",
"prepack": "pnpm build",
"build:esm": "tsc -p tsconfig.build.esm.json",
- "build:webpack": "webpack",
+ "build:webpack": "webpack -c webpack.config.mjs",
"clean": "rimraf esm dist *.tsbuildinfo",
"storybook": "storybook dev --port 6006",
"storybook:build": "storybook build"
diff --git a/products/jbrowse-react-circular-genome-view/webpack.config.js b/products/jbrowse-react-circular-genome-view/webpack.config.mjs
similarity index 91%
rename from products/jbrowse-react-circular-genome-view/webpack.config.js
rename to products/jbrowse-react-circular-genome-view/webpack.config.mjs
index 72a2f8b74e..14c8c373c0 100644
--- a/products/jbrowse-react-circular-genome-view/webpack.config.js
+++ b/products/jbrowse-react-circular-genome-view/webpack.config.mjs
@@ -1,7 +1,8 @@
-const path = require('path')
-const webpack = require('webpack')
+import path from 'path'
-module.exports = {
+import webpack from 'webpack'
+
+export default {
mode: process.env.NODE_ENV || 'production',
entry: './src/webpack.ts',
devtool: 'source-map',
diff --git a/products/jbrowse-react-circular-genome-view/.storybook/main.js b/products/jbrowse-react-linear-genome-view/.storybook/main.mjs
similarity index 88%
rename from products/jbrowse-react-circular-genome-view/.storybook/main.js
rename to products/jbrowse-react-linear-genome-view/.storybook/main.mjs
index 627b476745..1c5f4053a2 100644
--- a/products/jbrowse-react-circular-genome-view/.storybook/main.js
+++ b/products/jbrowse-react-linear-genome-view/.storybook/main.mjs
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
@@ -15,7 +15,7 @@ module.exports = {
test: /\.(ts|tsx|js|jsx)$/,
use: [
{
- loader: require.resolve('babel-loader'),
+ loader: 'babel-loader',
options: {
rootMode: 'upward',
},
diff --git a/products/jbrowse-react-linear-genome-view/.storybook/middleware.js b/products/jbrowse-react-linear-genome-view/.storybook/middleware.mjs
similarity index 66%
rename from products/jbrowse-react-linear-genome-view/.storybook/middleware.js
rename to products/jbrowse-react-linear-genome-view/.storybook/middleware.mjs
index 6640c0f2ff..e0738ac898 100644
--- a/products/jbrowse-react-linear-genome-view/.storybook/middleware.js
+++ b/products/jbrowse-react-linear-genome-view/.storybook/middleware.mjs
@@ -1,7 +1,7 @@
-const serveStatic = require('serve-static')
+import serveStatic from 'serve-static'
// the default static file serving fails on vcf files due to Content-Encoding
const expressMiddleWare = router => {
router.use(serveStatic('public'))
}
-module.exports = expressMiddleWare
+export default expressMiddleWare
diff --git a/products/jbrowse-react-linear-genome-view/package.json b/products/jbrowse-react-linear-genome-view/package.json
index 63f637c8f0..7c0032ea61 100644
--- a/products/jbrowse-react-linear-genome-view/package.json
+++ b/products/jbrowse-react-linear-genome-view/package.json
@@ -1,6 +1,7 @@
{
"name": "@jbrowse/react-linear-genome-view2",
"version": "4.0.3",
+ "type": "module",
"description": "JBrowse 2 linear genome view React component",
"keywords": [
"jbrowse",
@@ -33,7 +34,7 @@
"build": "pnpm run /^build:/",
"prepublishOnly": "node output-version.js > src/version.ts && git add -A src && git commit -m '[skip ci] Bump version.ts'",
"build:esm": "tsc --build tsconfig.build.esm.json",
- "build:webpack": "webpack",
+ "build:webpack": "webpack -c webpack.config.mjs",
"clean": "rimraf esm *.tsbuildinfo",
"storybook": "storybook dev --port 6006",
"storybook:build": "storybook build",
diff --git a/products/jbrowse-react-linear-genome-view/stories/examples/NextstrainExample.tsx b/products/jbrowse-react-linear-genome-view/stories/examples/NextstrainExample.tsx
index e16b83d83e..e97edbda48 100644
--- a/products/jbrowse-react-linear-genome-view/stories/examples/NextstrainExample.tsx
+++ b/products/jbrowse-react-linear-genome-view/stories/examples/NextstrainExample.tsx
@@ -1,4 +1,4 @@
-import nextstrainConfig from '../../public/nextstrain_covid.json'
+import nextstrainConfig from '../../public/nextstrain_covid.json' with { type: 'json' }
// in your code
// import { createViewState, loadPlugins, JBrowseLinearGenomeView } from '@jbrowse/react-linear-genome-view2'
import { JBrowseLinearGenomeView, createViewState } from '../../src/index.ts'
diff --git a/products/jbrowse-react-linear-genome-view/stories/examples/util.ts b/products/jbrowse-react-linear-genome-view/stories/examples/util.ts
index f5e96e2928..75e50df591 100644
--- a/products/jbrowse-react-linear-genome-view/stories/examples/util.ts
+++ b/products/jbrowse-react-linear-genome-view/stories/examples/util.ts
@@ -1,5 +1,5 @@
// configs
-import config from '../../public/test_data/volvox/config.json'
+import config from '../../public/test_data/volvox/config.json' with { type: 'json' }
export function addRelativeUris(config: any, baseUri: string) {
if (typeof config === 'object') {
diff --git a/products/jbrowse-react-linear-genome-view/webpack.config.js b/products/jbrowse-react-linear-genome-view/webpack.config.mjs
similarity index 91%
rename from products/jbrowse-react-linear-genome-view/webpack.config.js
rename to products/jbrowse-react-linear-genome-view/webpack.config.mjs
index 5d110c7e9c..97f7baff08 100644
--- a/products/jbrowse-react-linear-genome-view/webpack.config.js
+++ b/products/jbrowse-react-linear-genome-view/webpack.config.mjs
@@ -1,7 +1,8 @@
-const path = require('path')
-const webpack = require('webpack')
+import path from 'path'
-module.exports = {
+import webpack from 'webpack'
+
+export default {
mode: process.env.NODE_ENV || 'production',
entry: './src/webpack.ts',
devtool: 'source-map',
diff --git a/products/jbrowse-web/package.json b/products/jbrowse-web/package.json
index bcc1afe208..b506f8048d 100644
--- a/products/jbrowse-web/package.json
+++ b/products/jbrowse-web/package.json
@@ -6,6 +6,10 @@
"homepage": ".",
"main": "build",
"dir": "src",
+ "exports": {
+ "./src/rootModel/index.js": "./src/rootModel/index.ts",
+ "./src/makeWorkerInstance": "./src/makeWorkerInstance.ts"
+ },
"scripts": {
"start": "NODE_ENV=development node scripts/start.js",
"build": "NODE_ENV=production node scripts/build.js",
diff --git a/products/jbrowse-web/src/jbrowseModel.test.ts b/products/jbrowse-web/src/jbrowseModel.test.ts
index 2012bef123..49df047cee 100644
--- a/products/jbrowse-web/src/jbrowseModel.test.ts
+++ b/products/jbrowse-web/src/jbrowseModel.test.ts
@@ -4,7 +4,7 @@ import { getSnapshot } from '@jbrowse/mobx-state-tree'
import corePlugins from './corePlugins.ts'
import jbrowseModelFactory from './jbrowseModel.ts'
-import configSnapshot from '../test_data/volvox/config.json'
+import configSnapshot from '../test_data/volvox/config.json' with { type: 'json' }
type JBrowseModelType = ReturnType
diff --git a/products/jbrowse-web/src/rootModel/index.ts b/products/jbrowse-web/src/rootModel/index.ts
index 488040227f..8cab898efb 100644
--- a/products/jbrowse-web/src/rootModel/index.ts
+++ b/products/jbrowse-web/src/rootModel/index.ts
@@ -1,2 +1,2 @@
-export default './rootModel'
+export { default } from './rootModel.ts'
export { createTestSession } from './test_util.ts'
diff --git a/products/jbrowse-web/src/rootModel/rootModel.ts b/products/jbrowse-web/src/rootModel/rootModel.ts
index 30dd2fec6b..8ba2bcb8e8 100644
--- a/products/jbrowse-web/src/rootModel/rootModel.ts
+++ b/products/jbrowse-web/src/rootModel/rootModel.ts
@@ -39,7 +39,7 @@ import { formatDistanceToNow } from 'date-fns'
import { openDB } from 'idb'
import { autorun } from 'mobx'
-import packageJSON from '../../package.json'
+import packageJSON from '../../package.json' with { type: 'json' }
import jbrowseWebFactory from '../jbrowseModel.ts'
import makeWorkerInstance from '../makeWorkerInstance.ts'
import { filterSessionInPlace } from '../util.ts'
diff --git a/products/jbrowse-web/src/sessionSharing.ts b/products/jbrowse-web/src/sessionSharing.ts
index cf52a46470..f2b2296b6a 100644
--- a/products/jbrowse-web/src/sessionSharing.ts
+++ b/products/jbrowse-web/src/sessionSharing.ts
@@ -1,3 +1,5 @@
+import { aesDecrypt, aesEncrypt } from '@jbrowse/core/util'
+
import { toUrlSafeB64 } from './util.ts'
// from https://stackoverflow.com/questions/1349404/
@@ -12,18 +14,6 @@ function generateUID(length: number) {
.slice(0, length)
}
-const encrypt = async (text: string, password: string) => {
- const AES = await import('crypto-js/aes')
- return AES.encrypt(text, password).toString()
-}
-
-const decrypt = async (text: string, password: string) => {
- const AES = await import('crypto-js/aes')
- const Utf8 = await import('crypto-js/enc-utf8')
- const bytes = AES.decrypt(text, password)
- return bytes.toString(Utf8)
-}
-
function getErrorMsg(err: string) {
try {
const obj = JSON.parse(err)
@@ -40,7 +30,7 @@ export async function shareSessionToDynamo(
) {
const sess = await toUrlSafeB64(JSON.stringify(session))
const password = generateUID(5)
- const encryptedSession = await encrypt(sess, password)
+ const encryptedSession = await aesEncrypt(sess, password)
const data = new FormData()
data.append('session', encryptedSession)
@@ -83,5 +73,5 @@ export async function readSessionFromDynamo(
}
const json = await response.json()
- return decrypt(json.session, password)
+ return aesDecrypt(json.session, password)
}
diff --git a/products/jbrowse-web/src/tests/Alignments.test.tsx b/products/jbrowse-web/src/tests/Alignments.test.tsx
index 3d3b660029..0fb9178f6a 100644
--- a/products/jbrowse-web/src/tests/Alignments.test.tsx
+++ b/products/jbrowse-web/src/tests/Alignments.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/AlignmentsColorBy.test.tsx b/products/jbrowse-web/src/tests/AlignmentsColorBy.test.tsx
index 06dd460a50..fa6cd879a7 100644
--- a/products/jbrowse-web/src/tests/AlignmentsColorBy.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsColorBy.test.tsx
@@ -1,5 +1,5 @@
import { screen, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/AlignmentsFilters.test.tsx b/products/jbrowse-web/src/tests/AlignmentsFilters.test.tsx
index 07063b693c..9ec5e4c390 100644
--- a/products/jbrowse-web/src/tests/AlignmentsFilters.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsFilters.test.tsx
@@ -1,5 +1,5 @@
import { screen, waitFor, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/AlignmentsMethylation.test.tsx b/products/jbrowse-web/src/tests/AlignmentsMethylation.test.tsx
index dd4a650ada..e0b6af3646 100644
--- a/products/jbrowse-web/src/tests/AlignmentsMethylation.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsMethylation.test.tsx
@@ -2,7 +2,7 @@ import path from 'path'
import { testAlignmentModificationsDisplay } from './testAlignmentModificationsDisplay.tsx'
import { doBeforeEach, setup } from './util.tsx'
-import config from '../../test_data/methylation_test/config.json'
+import config from '../../test_data/methylation_test/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/AlignmentsModifications.test.tsx b/products/jbrowse-web/src/tests/AlignmentsModifications.test.tsx
index 89b9e3645d..3b61f92874 100644
--- a/products/jbrowse-web/src/tests/AlignmentsModifications.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsModifications.test.tsx
@@ -2,7 +2,7 @@ import path from 'path'
import { testAlignmentModificationsDisplay } from './testAlignmentModificationsDisplay.tsx'
import { doBeforeEach, setup } from './util.tsx'
-import config from '../../test_data/modifications_test/config.json'
+import config from '../../test_data/modifications_test/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/AlignmentsSoftClip.test.tsx b/products/jbrowse-web/src/tests/AlignmentsSoftClip.test.tsx
index db36181036..ac32617881 100644
--- a/products/jbrowse-web/src/tests/AlignmentsSoftClip.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsSoftClip.test.tsx
@@ -1,5 +1,5 @@
import { screen, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/AlignmentsSort.test.tsx b/products/jbrowse-web/src/tests/AlignmentsSort.test.tsx
index c1f32ad5dd..dde6e2fbed 100644
--- a/products/jbrowse-web/src/tests/AlignmentsSort.test.tsx
+++ b/products/jbrowse-web/src/tests/AlignmentsSort.test.tsx
@@ -1,5 +1,5 @@
import { screen, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/Authentication.test.tsx b/products/jbrowse-web/src/tests/Authentication.test.tsx
index 1357ca4498..28c62d3e75 100644
--- a/products/jbrowse-web/src/tests/Authentication.test.tsx
+++ b/products/jbrowse-web/src/tests/Authentication.test.tsx
@@ -9,7 +9,7 @@ import {
pv,
setup,
} from './util.tsx'
-import config from '../../test_data/volvox/config_auth.json'
+import config from '../../test_data/volvox/config_auth.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/AuthenticationHTTPBasic.test.tsx b/products/jbrowse-web/src/tests/AuthenticationHTTPBasic.test.tsx
index 1286a89abd..35b10725ca 100644
--- a/products/jbrowse-web/src/tests/AuthenticationHTTPBasic.test.tsx
+++ b/products/jbrowse-web/src/tests/AuthenticationHTTPBasic.test.tsx
@@ -8,7 +8,7 @@ import {
pv,
setup,
} from './util.tsx'
-import config from '../../test_data/volvox/config_auth.json'
+import config from '../../test_data/volvox/config_auth.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BookmarkWidget.test.tsx b/products/jbrowse-web/src/tests/BookmarkWidget.test.tsx
index 936a52c372..07d6bdee84 100644
--- a/products/jbrowse-web/src/tests/BookmarkWidget.test.tsx
+++ b/products/jbrowse-web/src/tests/BookmarkWidget.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, waitFor, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { saveAs } from 'file-saver-es'
import { createView, doBeforeEach, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitView.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitView.test.tsx
index 46ceee4c4a..6adae48a77 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitView.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitView.test.tsx
@@ -2,7 +2,7 @@ import '@testing-library/jest-dom'
import { waitFor } from '@testing-library/react'
import { createView, doBeforeEach, mockConsoleWarn, setup } from './util.tsx'
-import breakpointConfig from '../../test_data/breakpoint/config.json'
+import breakpointConfig from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitViewInit1.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitViewInit1.test.tsx
index 7aa80b5081..0146f14b1f 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitViewInit1.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitViewInit1.test.tsx
@@ -5,7 +5,7 @@ import { LocalFile } from 'generic-filehandle2'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/breakpoint/config.json'
+import configSnapshot from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitViewInit2.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitViewInit2.test.tsx
index ef83502e51..2d6bff723c 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitViewInit2.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitViewInit2.test.tsx
@@ -5,7 +5,7 @@ import { LocalFile } from 'generic-filehandle2'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/breakpoint/config.json'
+import configSnapshot from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitViewInit3.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitViewInit3.test.tsx
index c9fd03a439..b595d71168 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitViewInit3.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitViewInit3.test.tsx
@@ -5,7 +5,7 @@ import { LocalFile } from 'generic-filehandle2'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/breakpoint/config.json'
+import configSnapshot from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitViewInit4.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitViewInit4.test.tsx
index 48bda3a934..1431b783e4 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitViewInit4.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitViewInit4.test.tsx
@@ -5,7 +5,7 @@ import { LocalFile } from 'generic-filehandle2'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/breakpoint/config.json'
+import configSnapshot from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/BreakpointSplitViewInit5.test.tsx b/products/jbrowse-web/src/tests/BreakpointSplitViewInit5.test.tsx
index 5ff92149f6..ae0e5076a2 100644
--- a/products/jbrowse-web/src/tests/BreakpointSplitViewInit5.test.tsx
+++ b/products/jbrowse-web/src/tests/BreakpointSplitViewInit5.test.tsx
@@ -4,7 +4,7 @@ import { LocalFile } from 'generic-filehandle2'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/breakpoint/config.json'
+import configSnapshot from '../../test_data/breakpoint/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/CircularView.test.tsx b/products/jbrowse-web/src/tests/CircularView.test.tsx
index a534d99688..cec8dcb3da 100644
--- a/products/jbrowse-web/src/tests/CircularView.test.tsx
+++ b/products/jbrowse-web/src/tests/CircularView.test.tsx
@@ -2,7 +2,7 @@ import '@testing-library/jest-dom'
import { fireEvent, waitFor } from '@testing-library/react'
import { createView, doBeforeEach, hts, setup } from './util.tsx'
-import configSnapshot from '../../test_data/volvox/config.json'
+import configSnapshot from '../../test_data/volvox/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/CollapseIntrons.test.tsx b/products/jbrowse-web/src/tests/CollapseIntrons.test.tsx
index f50222f681..88cd171c23 100644
--- a/products/jbrowse-web/src/tests/CollapseIntrons.test.tsx
+++ b/products/jbrowse-web/src/tests/CollapseIntrons.test.tsx
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import { fireEvent, screen, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { createView, doBeforeEach, hts, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/ConfigurationEditor.test.tsx b/products/jbrowse-web/src/tests/ConfigurationEditor.test.tsx
index c5be159b90..bc6666ccb1 100644
--- a/products/jbrowse-web/src/tests/ConfigurationEditor.test.tsx
+++ b/products/jbrowse-web/src/tests/ConfigurationEditor.test.tsx
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import { waitFor } from '@testing-library/dom'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/Connection.test.tsx b/products/jbrowse-web/src/tests/Connection.test.tsx
index 4c8a39f40d..70ca480feb 100644
--- a/products/jbrowse-web/src/tests/Connection.test.tsx
+++ b/products/jbrowse-web/src/tests/Connection.test.tsx
@@ -1,9 +1,9 @@
import { screen, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { LocalFile } from 'generic-filehandle2'
import { createView, doBeforeEach, generateReadBuffer } from './util.tsx'
-import configSnapshot from '../../test_data/volvox/config.json'
+import configSnapshot from '../../test_data/volvox/config.json' with { type: 'json' }
jest.mock('../makeWorkerInstance', () => () => {})
diff --git a/products/jbrowse-web/src/tests/CopyAndDelete.test.tsx b/products/jbrowse-web/src/tests/CopyAndDelete.test.tsx
index f4427f1ae2..eedcb71172 100644
--- a/products/jbrowse-web/src/tests/CopyAndDelete.test.tsx
+++ b/products/jbrowse-web/src/tests/CopyAndDelete.test.tsx
@@ -10,7 +10,7 @@ import {
mockConsoleWarn,
setup,
} from './util.tsx'
-import masterConfig from '../../test_data/volvox/connection_test.json'
+import masterConfig from '../../test_data/volvox/connection_test.json' with { type: 'json' }
setup()
beforeEach(() => {
diff --git a/products/jbrowse-web/src/tests/Dotplot.test.tsx b/products/jbrowse-web/src/tests/Dotplot.test.tsx
index ba93daaa55..611e72609c 100644
--- a/products/jbrowse-web/src/tests/Dotplot.test.tsx
+++ b/products/jbrowse-web/src/tests/Dotplot.test.tsx
@@ -1,9 +1,9 @@
import path from 'path'
-import dotplotSessionFlipAxes from './dotplot_inverted_flipaxes.json'
-import dotplotSession from './dotplot_inverted_test.json'
+import dotplotSessionFlipAxes from './dotplot_inverted_flipaxes.json' with { type: 'json' }
+import dotplotSession from './dotplot_inverted_test.json' with { type: 'json' }
import { createView, doBeforeEach, expectCanvasMatch, setup } from './util.tsx'
-import config from '../../test_data/config_dotplot.json'
+import config from '../../test_data/config_dotplot.json' with { type: 'json' }
const delay = { timeout: 50000 }
const opts = [{}, delay]
diff --git a/products/jbrowse-web/src/tests/DotplotOpenLinearSyntenyView.test.tsx b/products/jbrowse-web/src/tests/DotplotOpenLinearSyntenyView.test.tsx
index ac6ab2689e..4b2ccb3790 100644
--- a/products/jbrowse-web/src/tests/DotplotOpenLinearSyntenyView.test.tsx
+++ b/products/jbrowse-web/src/tests/DotplotOpenLinearSyntenyView.test.tsx
@@ -4,7 +4,7 @@ import { configure } from 'mobx'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/grape_peach_synteny/config.json'
+import configSnapshot from '../../test_data/grape_peach_synteny/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/DotplotViewInit.test.tsx b/products/jbrowse-web/src/tests/DotplotViewInit.test.tsx
index c2c8187360..d93be23597 100644
--- a/products/jbrowse-web/src/tests/DotplotViewInit.test.tsx
+++ b/products/jbrowse-web/src/tests/DotplotViewInit.test.tsx
@@ -4,7 +4,7 @@ import { configure } from 'mobx'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/grape_peach_synteny/config.json'
+import configSnapshot from '../../test_data/grape_peach_synteny/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/Empty.test.tsx b/products/jbrowse-web/src/tests/Empty.test.tsx
index b34dcbd19e..052df82d2c 100644
--- a/products/jbrowse-web/src/tests/Empty.test.tsx
+++ b/products/jbrowse-web/src/tests/Empty.test.tsx
@@ -1,7 +1,7 @@
import { render } from '@testing-library/react'
import { JBrowse, getPluginManager } from './util.tsx'
-import emptyConfig from '../../test_data/empty.json'
+import emptyConfig from '../../test_data/empty.json' with { type: 'json' }
test('catches no assemblies with empty config', async () => {
const pluginManager = getPluginManager(emptyConfig)
diff --git a/products/jbrowse-web/src/tests/ErrorConditions.test.tsx b/products/jbrowse-web/src/tests/ErrorConditions.test.tsx
index 6e94790602..52eea85dda 100644
--- a/products/jbrowse-web/src/tests/ErrorConditions.test.tsx
+++ b/products/jbrowse-web/src/tests/ErrorConditions.test.tsx
@@ -1,6 +1,6 @@
import { createViewNoWait, doBeforeEach, mockConsole } from './util.tsx'
-import chromeSizesConfig from '../../test_data/404_chrom_sizes/config.json'
-import wrongAssemblyTest from '../../test_data/wrong_assembly.json'
+import chromeSizesConfig from '../../test_data/404_chrom_sizes/config.json' with { type: 'json' }
+import wrongAssemblyTest from '../../test_data/wrong_assembly.json' with { type: 'json' }
const delay = { timeout: 30000 }
diff --git a/products/jbrowse-web/src/tests/ExportSession.test.tsx b/products/jbrowse-web/src/tests/ExportSession.test.tsx
index ab4fe699e7..c017b04e72 100644
--- a/products/jbrowse-web/src/tests/ExportSession.test.tsx
+++ b/products/jbrowse-web/src/tests/ExportSession.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { saveAs } from 'file-saver-es'
let mockCounter = 0
diff --git a/products/jbrowse-web/src/tests/ExportSvgBreakpointSplitView.test.tsx b/products/jbrowse-web/src/tests/ExportSvgBreakpointSplitView.test.tsx
index e889731e1e..fdbc668da8 100644
--- a/products/jbrowse-web/src/tests/ExportSvgBreakpointSplitView.test.tsx
+++ b/products/jbrowse-web/src/tests/ExportSvgBreakpointSplitView.test.tsx
@@ -1,5 +1,5 @@
import { createView, doBeforeEach, exportAndVerifySvg, setup } from './util.tsx'
-import breakpointConfig from '../../test_data/breakpoint/config.json'
+import breakpointConfig from '../../test_data/breakpoint/config.json' with { type: 'json' }
// @ts-expect-error
global.Blob = (content, options) => ({ content, options })
diff --git a/products/jbrowse-web/src/tests/ExportSvgCircular.test.tsx b/products/jbrowse-web/src/tests/ExportSvgCircular.test.tsx
index 397377f70e..7090952c41 100644
--- a/products/jbrowse-web/src/tests/ExportSvgCircular.test.tsx
+++ b/products/jbrowse-web/src/tests/ExportSvgCircular.test.tsx
@@ -7,7 +7,7 @@ import {
hts,
setup,
} from './util.tsx'
-import volvoxConfig from '../../test_data/volvox/config.json'
+import volvoxConfig from '../../test_data/volvox/config.json' with { type: 'json' }
// @ts-expect-error
global.Blob = (content, options) => ({ content, options })
diff --git a/products/jbrowse-web/src/tests/ExportSvgDotplot.test.tsx b/products/jbrowse-web/src/tests/ExportSvgDotplot.test.tsx
index fd7a9c8815..80561c9e08 100644
--- a/products/jbrowse-web/src/tests/ExportSvgDotplot.test.tsx
+++ b/products/jbrowse-web/src/tests/ExportSvgDotplot.test.tsx
@@ -1,5 +1,5 @@
import { createView, doBeforeEach, exportAndVerifySvg, setup } from './util.tsx'
-import volvoxConfig from '../../test_data/volvox/config.json'
+import volvoxConfig from '../../test_data/volvox/config.json' with { type: 'json' }
// @ts-expect-error
global.Blob = (content, options) => ({ content, options })
diff --git a/products/jbrowse-web/src/tests/ExportSvgLinearSyntenyView.test.tsx b/products/jbrowse-web/src/tests/ExportSvgLinearSyntenyView.test.tsx
index 9ce23416a9..8f7d5d69fe 100644
--- a/products/jbrowse-web/src/tests/ExportSvgLinearSyntenyView.test.tsx
+++ b/products/jbrowse-web/src/tests/ExportSvgLinearSyntenyView.test.tsx
@@ -11,7 +11,7 @@ import {
mockConsoleWarn,
setup,
} from './util.tsx'
-import volvoxConfig from '../../test_data/volvox/config.json'
+import volvoxConfig from '../../test_data/volvox/config.json' with { type: 'json' }
// @ts-expect-error
global.Blob = (content, options) => ({ content, options })
diff --git a/products/jbrowse-web/src/tests/GCContent.test.tsx b/products/jbrowse-web/src/tests/GCContent.test.tsx
index 3c00f047b1..a5f1e70767 100644
--- a/products/jbrowse-web/src/tests/GCContent.test.tsx
+++ b/products/jbrowse-web/src/tests/GCContent.test.tsx
@@ -1,5 +1,5 @@
import { screen, within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/Hic.test.tsx b/products/jbrowse-web/src/tests/Hic.test.tsx
index e19bb86c08..8f0a44288d 100644
--- a/products/jbrowse-web/src/tests/Hic.test.tsx
+++ b/products/jbrowse-web/src/tests/Hic.test.tsx
@@ -7,7 +7,7 @@ import {
hts,
setup,
} from './util.tsx'
-import hicConfig from '../../../../extra_test_data/hic_integration_test.json'
+import hicConfig from '../../../../extra_test_data/hic_integration_test.json' with { type: 'json' }
beforeEach(() => {
doBeforeEach(url => require.resolve(`../../../../extra_test_data/${url}`))
diff --git a/products/jbrowse-web/src/tests/JBrowse.test.tsx b/products/jbrowse-web/src/tests/JBrowse.test.tsx
index cfb23c3829..c6cdf5fbde 100644
--- a/products/jbrowse-web/src/tests/JBrowse.test.tsx
+++ b/products/jbrowse-web/src/tests/JBrowse.test.tsx
@@ -4,7 +4,7 @@ import PluginManager from '@jbrowse/core/PluginManager'
import { getConf, readConfObject } from '@jbrowse/core/configuration'
import { fireEvent } from '@testing-library/react'
-import volvoxConfigSnapshot from '../../test_data/volvox/config.json'
+import volvoxConfigSnapshot from '../../test_data/volvox/config.json' with { type: 'json' }
import corePlugins from '../corePlugins.ts'
import TestPlugin from './TestPlugin.ts'
import {
diff --git a/products/jbrowse-web/src/tests/LDDisplay.test.tsx b/products/jbrowse-web/src/tests/LDDisplay.test.tsx
index c30d12b6ce..48e2da2314 100644
--- a/products/jbrowse-web/src/tests/LDDisplay.test.tsx
+++ b/products/jbrowse-web/src/tests/LDDisplay.test.tsx
@@ -30,6 +30,7 @@ test(
fireEvent.click(await findByText('Display types', ...opts))
fireEvent.click(await findByText('LD heatmap display', ...opts))
+ await new Promise(res => setTimeout(res, 3000))
expectCanvasMatch(await findByTestId('ld_canvas_done', ...opts))
},
timeout,
diff --git a/products/jbrowse-web/src/tests/LGVSynteny.test.tsx b/products/jbrowse-web/src/tests/LGVSynteny.test.tsx
index 22b5e58d72..a3222d536c 100644
--- a/products/jbrowse-web/src/tests/LGVSynteny.test.tsx
+++ b/products/jbrowse-web/src/tests/LGVSynteny.test.tsx
@@ -1,6 +1,6 @@
import { getEnv } from '@jbrowse/core/util'
import { fireEvent, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/LinearSyntenyViewInit.test.tsx b/products/jbrowse-web/src/tests/LinearSyntenyViewInit.test.tsx
index 057f309f57..351a89cd27 100644
--- a/products/jbrowse-web/src/tests/LinearSyntenyViewInit.test.tsx
+++ b/products/jbrowse-web/src/tests/LinearSyntenyViewInit.test.tsx
@@ -4,7 +4,7 @@ import { configure } from 'mobx'
import { handleRequest } from './generateReadBuffer.ts'
import { getPluginManager, setup } from './util.tsx'
-import configSnapshot from '../../test_data/grape_peach_synteny/config.json'
+import configSnapshot from '../../test_data/grape_peach_synteny/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/NcbiAliasAdapter.test.tsx b/products/jbrowse-web/src/tests/NcbiAliasAdapter.test.tsx
index 3a6e9f70b7..6396b964d1 100644
--- a/products/jbrowse-web/src/tests/NcbiAliasAdapter.test.tsx
+++ b/products/jbrowse-web/src/tests/NcbiAliasAdapter.test.tsx
@@ -1,5 +1,5 @@
import { createView, doBeforeEach, expectCanvasMatch, setup } from './util.tsx'
-import config from '../../test_data/cfam2/config.json'
+import config from '../../test_data/cfam2/config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/SNPCoverage.test.tsx b/products/jbrowse-web/src/tests/SNPCoverage.test.tsx
index cdefa7bfef..93a48a99a8 100644
--- a/products/jbrowse-web/src/tests/SNPCoverage.test.tsx
+++ b/products/jbrowse-web/src/tests/SNPCoverage.test.tsx
@@ -1,5 +1,5 @@
import { within } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/SaveTrackData.test.tsx b/products/jbrowse-web/src/tests/SaveTrackData.test.tsx
index 06a9affa0a..1b19442f4a 100644
--- a/products/jbrowse-web/src/tests/SaveTrackData.test.tsx
+++ b/products/jbrowse-web/src/tests/SaveTrackData.test.tsx
@@ -2,7 +2,7 @@ import fs from 'fs'
import path from 'path'
import { screen, waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { saveAs } from 'file-saver-es'
import { createView, doBeforeEach, hts, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/Spreadsheet.test.tsx b/products/jbrowse-web/src/tests/Spreadsheet.test.tsx
index 149b73b6cb..c95abc7a16 100644
--- a/products/jbrowse-web/src/tests/Spreadsheet.test.tsx
+++ b/products/jbrowse-web/src/tests/Spreadsheet.test.tsx
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import { screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { doBeforeEach, openSpreadsheetView, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/SubfeatureClick.test.tsx b/products/jbrowse-web/src/tests/SubfeatureClick.test.tsx
index 1de18357e9..8ab869519a 100644
--- a/products/jbrowse-web/src/tests/SubfeatureClick.test.tsx
+++ b/products/jbrowse-web/src/tests/SubfeatureClick.test.tsx
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import { fireEvent, screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { createView, doBeforeEach, hts, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/SubfeatureLabels.test.tsx b/products/jbrowse-web/src/tests/SubfeatureLabels.test.tsx
index 881200e786..689d458711 100644
--- a/products/jbrowse-web/src/tests/SubfeatureLabels.test.tsx
+++ b/products/jbrowse-web/src/tests/SubfeatureLabels.test.tsx
@@ -1,5 +1,5 @@
import { screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import {
createView,
diff --git a/products/jbrowse-web/src/tests/TextSearching.test.tsx b/products/jbrowse-web/src/tests/TextSearching.test.tsx
index ed9425c5e8..11dd15eeea 100644
--- a/products/jbrowse-web/src/tests/TextSearching.test.tsx
+++ b/products/jbrowse-web/src/tests/TextSearching.test.tsx
@@ -1,7 +1,7 @@
import { fireEvent, waitFor, within } from '@testing-library/react'
import { createView, doBeforeEach, setup } from './util.tsx'
-import jb1_config from '../../test_data/volvox/volvox_jb1_text_config.json'
+import jb1_config from '../../test_data/volvox/volvox_jb1_text_config.json' with { type: 'json' }
setup()
diff --git a/products/jbrowse-web/src/tests/TrackMenu.test.tsx b/products/jbrowse-web/src/tests/TrackMenu.test.tsx
index 0a6489e3c7..b92184f15d 100644
--- a/products/jbrowse-web/src/tests/TrackMenu.test.tsx
+++ b/products/jbrowse-web/src/tests/TrackMenu.test.tsx
@@ -1,5 +1,5 @@
import { screen } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { createView, doBeforeEach, hts, setup } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/testLinkedReadsDisplay.tsx b/products/jbrowse-web/src/tests/testLinkedReadsDisplay.tsx
index c16416990f..cfe82bf695 100644
--- a/products/jbrowse-web/src/tests/testLinkedReadsDisplay.tsx
+++ b/products/jbrowse-web/src/tests/testLinkedReadsDisplay.tsx
@@ -1,5 +1,5 @@
import { waitFor } from '@testing-library/react'
-import userEvent from '@testing-library/user-event'
+import { userEvent } from '@testing-library/user-event'
import { createView, expectCanvasMatch, hts } from './util.tsx'
diff --git a/products/jbrowse-web/src/tests/tracks.test.ts b/products/jbrowse-web/src/tests/tracks.test.ts
index 324ef90ab0..7eae31ced3 100644
--- a/products/jbrowse-web/src/tests/tracks.test.ts
+++ b/products/jbrowse-web/src/tests/tracks.test.ts
@@ -1,5 +1,6 @@
import { guessAdapter as guessAdapter2 } from '@jbrowse/core/util/tracks'
-import { createTestSession } from '@jbrowse/web/src/rootModel'
+
+import { createTestSession } from '../rootModel/index.ts'
jest.mock('../makeWorkerInstance', () => () => {})
diff --git a/products/jbrowse-web/src/tests/util.tsx b/products/jbrowse-web/src/tests/util.tsx
index 2fda46c814..81b8e80f19 100644
--- a/products/jbrowse-web/src/tests/util.tsx
+++ b/products/jbrowse-web/src/tests/util.tsx
@@ -12,7 +12,7 @@ import { LocalFile } from 'generic-filehandle2'
import { toMatchImageSnapshot } from 'jest-image-snapshot'
import { generateReadBuffer } from './generateReadBuffer.ts'
-import configSnapshot from '../../test_data/volvox/config.json'
+import configSnapshot from '../../test_data/volvox/config.json' with { type: 'json' }
import corePlugins from '../corePlugins.ts'
import JBrowse from './TestingJBrowse.tsx'
import JBrowseRootModelFactory from '../rootModel/rootModel.ts'
diff --git a/products/jbrowse-web/tsconfig.oauth.json b/products/jbrowse-web/tsconfig.oauth.json
index d94b864fa6..2e10a2244c 100644
--- a/products/jbrowse-web/tsconfig.oauth.json
+++ b/products/jbrowse-web/tsconfig.oauth.json
@@ -1,6 +1,6 @@
{
"include": ["src/tests/oauthServer"],
"compilerOptions": {
- "module": "nodenext"
+ "module": "esnext"
}
}
diff --git a/scripts/pack.ts b/scripts/pack.ts
index a7e0bf733b..7060aa654c 100644
--- a/scripts/pack.ts
+++ b/scripts/pack.ts
@@ -21,7 +21,7 @@ for (const dir of workspaceDirs) {
const pkgJsonPath = path.join(pkgDir, 'package.json')
if (fs.existsSync(pkgJsonPath)) {
const location = pkgDir
- const { signal, status } = spawn.sync('pnpm', ['pack'], {
+ const { signal, status } = spawn.sync('pnpm', ['pack', '--silent'], {
stdio: 'inherit',
cwd: location,
})
diff --git a/webpack/config/webpack/persistentCache/createEnvironmentHash.js b/webpack/config/webpack/persistentCache/createEnvironmentHash.mjs
similarity index 51%
rename from webpack/config/webpack/persistentCache/createEnvironmentHash.js
rename to webpack/config/webpack/persistentCache/createEnvironmentHash.mjs
index e08ebab98c..75ad2cd0f1 100644
--- a/webpack/config/webpack/persistentCache/createEnvironmentHash.js
+++ b/webpack/config/webpack/persistentCache/createEnvironmentHash.mjs
@@ -1,6 +1,6 @@
-const { createHash } = require('crypto')
+import { createHash } from 'crypto'
-module.exports = function createEnvironmentHash(env) {
+export default function createEnvironmentHash(env) {
const hash = createHash('md5')
hash.update(JSON.stringify(env))