diff --git a/SequenceAnalysis/api-src/org/labkey/api/sequenceanalysis/run/AbstractGatk4Wrapper.java b/SequenceAnalysis/api-src/org/labkey/api/sequenceanalysis/run/AbstractGatk4Wrapper.java index 91959921b..29ac8b8ee 100644 --- a/SequenceAnalysis/api-src/org/labkey/api/sequenceanalysis/run/AbstractGatk4Wrapper.java +++ b/SequenceAnalysis/api-src/org/labkey/api/sequenceanalysis/run/AbstractGatk4Wrapper.java @@ -91,6 +91,7 @@ public List getBaseArgs(@Nullable String toolName) args.add(SequencePipelineService.get().getJavaFilepath()); args.addAll(SequencePipelineService.get().getJavaOpts(_maxRamOverride)); args.add("-DGATK_STACKTRACE_ON_USER_EXCEPTION=true"); + args.add("-Dsamjdk.optimistic_vcf_4_4=true"); args.add("-jar"); args.add(getJAR().getPath()); diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/util/FastqcRunner.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/util/FastqcRunner.java index 17c0fb2d4..58f6be91a 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/util/FastqcRunner.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/util/FastqcRunner.java @@ -17,16 +17,16 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Test; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleLoader; import org.labkey.api.pipeline.PipelineJobService; -import org.labkey.api.resource.FileResource; import org.labkey.api.resource.DirectoryResource; +import org.labkey.api.resource.FileResource; import org.labkey.api.resource.Resource; import org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService; import org.labkey.api.settings.AppProps; diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/KingInferenceStep.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/KingInferenceStep.java index 9a21691b5..66e61f3a9 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/KingInferenceStep.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/KingInferenceStep.java @@ -115,6 +115,10 @@ public Output processVariants(File inputVCF, File outputDirectory, ReferenceGeno plinkArgs.add("--max-alleles"); plinkArgs.add("2"); + // NOTE: tools like sawfish can report half-called genotypes, like 0/.. For now, be most conservative in PCA: + plinkArgs.add("--vcf-half-call"); + plinkArgs.add("missing"); + Integer threads = SequencePipelineService.get().getMaxThreads(getPipelineCtx().getLogger()); if (threads != null) { diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/PlinkPcaStep.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/PlinkPcaStep.java index 63d1d3315..a6aa4c6dd 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/PlinkPcaStep.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/run/variant/PlinkPcaStep.java @@ -227,6 +227,10 @@ private void runBatch(File inputVCF, File outputDirectory, VariantProcessingStep args.add(String.valueOf(maxRam)); } + // NOTE: tools like sawfish can report half-called genotypes, like 0/.. For now, be most conservative in PCA: + args.add("--vcf-half-call"); + args.add("missing"); + args.addAll(getClientCommandArgs()); getWrapper().execute(args); diff --git a/Studies/resources/queries/studies/studies/.qview.xml b/Studies/resources/queries/studies/studies/.qview.xml new file mode 100644 index 000000000..a694c9520 --- /dev/null +++ b/Studies/resources/queries/studies/studies/.qview.xml @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/Studies/resources/schemas/studies.xml b/Studies/resources/schemas/studies.xml index fd0d0a189..5dbd8d185 100644 --- a/Studies/resources/schemas/studies.xml +++ b/Studies/resources/schemas/studies.xml @@ -132,6 +132,7 @@ DETAILED + Study Id true false false diff --git a/Studies/resources/views/studiesOverview.html b/Studies/resources/views/studiesOverview.html index f257fc184..2d1d6a280 100644 --- a/Studies/resources/views/studiesOverview.html +++ b/Studies/resources/views/studiesOverview.html @@ -12,7 +12,7 @@ name: 'query', schemaName: 'studies', queryName: 'studies', - maxRows: 20 + maxRows: 10 }).render(webpart.wrapperDivId + '-studies'); // LABKEY.Query.selectRows({ @@ -62,4 +62,5 @@ }(jQuery, LABKEY)); +
Below is a list of the studies tracked in this folder. Please use the Data Browser tab to browse the dataset tracked in this project.
diff --git a/Studies/src/org/labkey/studies/query/LookupSetTable.java b/Studies/src/org/labkey/studies/query/LookupSetTable.java index b333008f3..022fc5802 100644 --- a/Studies/src/org/labkey/studies/query/LookupSetTable.java +++ b/Studies/src/org/labkey/studies/query/LookupSetTable.java @@ -22,7 +22,6 @@ import org.labkey.api.ldk.LDKService; import org.labkey.api.ldk.table.AbstractDataDefinedTable; import org.labkey.api.query.QueryUpdateService; -import org.labkey.api.query.SimpleUserSchema; import java.util.Map; @@ -101,15 +100,7 @@ public LookupSetTable init() @Override public QueryUpdateService getUpdateService() { - return new EHRLookupsUpdateService(this); - } - - protected class EHRLookupsUpdateService extends UpdateService - { - public EHRLookupsUpdateService(SimpleUserSchema.SimpleTable ti) - { - super(ti); - } + return new UpdateService(this); } } diff --git a/Studies/src/org/labkey/studies/query/StudiesUserSchema.java b/Studies/src/org/labkey/studies/query/StudiesUserSchema.java index 715d4aa0c..928d882c6 100644 --- a/Studies/src/org/labkey/studies/query/StudiesUserSchema.java +++ b/Studies/src/org/labkey/studies/query/StudiesUserSchema.java @@ -1,5 +1,6 @@ package org.labkey.studies.query; +import com.google.gwt.user.client.ui.TabBar; import org.apache.logging.log4j.Logger; import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.collections.CaseInsensitiveTreeSet; @@ -7,12 +8,15 @@ import org.labkey.api.data.Container; import org.labkey.api.data.ContainerFilter; import org.labkey.api.data.DbSchema; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.SQLFragment; import org.labkey.api.data.SchemaTableInfo; import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; import org.labkey.api.ldk.table.ContainerScopedTable; import org.labkey.api.ldk.table.CustomPermissionsTable; +import org.labkey.api.query.ExprColumn; import org.labkey.api.query.FieldKey; import org.labkey.api.query.QueryDefinition; import org.labkey.api.query.QueryException; @@ -134,7 +138,7 @@ else if (TABLE_LOOKUPS.equalsIgnoreCase(name)) } else if (TABLE_STUDIES.equalsIgnoreCase(name)) { - return createStudyDesignTable(name, cf, false); + return createStudiesTable(name, cf, false); } else if (TABLE_COHORTS.equalsIgnoreCase(name)) { @@ -165,7 +169,22 @@ else if (TABLE_EVENT_TYPES.equalsIgnoreCase(name)) return super.createTable(name, cf); } - private TableInfo createStudyDesignTable(String name, ContainerFilter cf, boolean addTriggers) + private TableInfo createStudiesTable(String name, ContainerFilter cf, boolean addTriggers) + { + CustomPermissionsTable ret = createStudyDesignTable(name, cf, addTriggers); + + final String chr = ret.getSqlDialect().isPostgreSQL() ? "chr" : "char"; + SQLFragment sql1 = new SQLFragment("(SELECT ").append(ret.getSqlDialect().getGroupConcat(new SQLFragment("c.label"), true, true, new SQLFragment(chr + "(10)"))).append(" as expr FROM " + StudiesSchema.NAME + "." + TABLE_COHORTS + " c WHERE c.studyId = " + ExprColumn.STR_TABLE_ALIAS + ".rowId)"); + ExprColumn col1 = new ExprColumn(ret, "cohorts", sql1, JdbcType.VARCHAR, ret.getColumn("rowid")); + col1.setLabel("Cohort(s)"); + col1.setDescription("This column lists the cohort labels for this study"); + + ret.addColumn(col1); + + return ret; + } + + private CustomPermissionsTable createStudyDesignTable(String name, ContainerFilter cf, boolean addTriggers) { CustomPermissionsTable ret = new CustomPermissionsTable<>(this, createSourceTable(name), cf); ret.addPermissionMapping(InsertPermission.class, StudiesDataAdminPermission.class); diff --git a/jbrowse/build.gradle b/jbrowse/build.gradle index 4de29862b..0e597ab4e 100644 --- a/jbrowse/build.gradle +++ b/jbrowse/build.gradle @@ -30,7 +30,7 @@ dependencies { external "org.apache.lucene:lucene-backward-codecs:${luceneVersion}" } -def jbPkgTask = project.tasks.named("npm_run_jb-pkg") +def jbPkgTask = project.tasks.named("npm_run_jb-sea") jbPkgTask.configure { outputs.cacheIf {false} diff --git a/jbrowse/package-lock.json b/jbrowse/package-lock.json index b2b8218e0..5a1abd52f 100644 --- a/jbrowse/package-lock.json +++ b/jbrowse/package-lock.json @@ -18,7 +18,6 @@ "@labkey/api": "^1.39.0", "@labkey/components": "^6.32.2", "@mui/x-data-grid": "^7.28.1", - "@yao-pkg/pkg": "^6.3.2", "assert": "^2.1.0", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", @@ -48,7 +47,9 @@ "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", "rimraf": "^6.0.1", - "typescript": "^5.1.6" + "tar": "^7.4.3", + "typescript": "^5.1.6", + "unzipper": "^0.12.3" } }, "node_modules/@adobe/css-tools": { @@ -2218,6 +2219,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2234,6 +2236,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, "engines": { "node": ">=12" }, @@ -2245,6 +2248,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { "node": ">=12" }, @@ -2255,12 +2259,14 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2277,6 +2283,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2291,6 +2298,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2307,6 +2315,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, "dependencies": { "minipass": "^7.0.4" }, @@ -3827,6 +3836,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true, "engines": { "node": ">=14" @@ -4517,73 +4527,6 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "node_modules/@yao-pkg/pkg": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.3.2.tgz", - "integrity": "sha512-gd4fh8dVC5qnKQD8HTwQrVLvT8TyQqwE59ky3LHtnke+6fBcTTrWavtbsVOwdL09IWqY+eSB+2AGCrSUnZ4wwg==", - "dependencies": { - "@babel/generator": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "@yao-pkg/pkg-fetch": "3.5.19", - "into-stream": "^6.0.0", - "minimist": "^1.2.6", - "multistream": "^4.1.0", - "picocolors": "^1.1.0", - "picomatch": "^4.0.2", - "prebuild-install": "^7.1.1", - "resolve": "^1.22.10", - "stream-meter": "^1.0.4", - "tar": "^7.4.3", - "tinyglobby": "^0.2.11", - "unzipper": "^0.12.3" - }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@yao-pkg/pkg-fetch": { - "version": "3.5.19", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.19.tgz", - "integrity": "sha512-EEURrS1Q5sSSAwaQ4zD0wZsquDiG8CroY3SCi7jYBoM0NG3eRA239mW6YMUYPNWUK4zCMhuK3bzFT5aIZP/rDg==", - "dependencies": { - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "picocolors": "^1.1.0", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" - } - }, - "node_modules/@yao-pkg/pkg-fetch/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@yao-pkg/pkg/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -4640,17 +4583,6 @@ "node": ">=8.9" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ajv": { "version": "8.17.1", "license": "MIT", @@ -4978,6 +4910,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/base64-arraybuffer": { @@ -5032,53 +4965,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bl": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" }, "node_modules/bn.js": { "version": "5.2.1", @@ -5156,6 +5048,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -5513,10 +5406,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/chownr": { - "version": "1.1.4", - "license": "ISC" - }, "node_modules/chrome-trace-event": { "version": "1.0.4", "license": "MIT", @@ -5572,16 +5461,6 @@ "node": ">=0.10.0" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -5920,6 +5799,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6218,19 +6098,6 @@ } } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-equal": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", @@ -6250,13 +6117,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deepmerge": { "version": "4.3.1", "license": "MIT", @@ -6377,13 +6237,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-libc": { - "version": "2.0.3", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, "node_modules/detect-node": { "version": "2.1.0", "license": "MIT" @@ -6544,12 +6397,15 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { "readable-stream": "^2.0.2" } }, "node_modules/eastasianwidth": { "version": "0.2.0", + "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -6584,6 +6440,7 @@ }, "node_modules/emoji-regex": { "version": "8.0.0", + "dev": true, "license": "MIT" }, "node_modules/emojis-list": { @@ -6603,13 +6460,6 @@ "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.17.1", "license": "MIT", @@ -6785,13 +6635,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, "node_modules/express": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", @@ -7013,6 +6856,7 @@ }, "node_modules/foreground-child": { "version": "3.3.0", + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", @@ -7027,6 +6871,7 @@ }, "node_modules/foreground-child/node_modules/signal-exit": { "version": "4.1.0", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -7219,26 +7064,16 @@ "node": ">= 0.6" } }, - "node_modules/from2": { - "version": "2.3.0", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, "node_modules/fs": { "version": "0.0.1-security", "license": "ISC" }, - "node_modules/fs-constants": { - "version": "1.0.0", - "license": "MIT" - }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -7299,14 +7134,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -7358,10 +7185,6 @@ "resolved": "https://registry.npmjs.org/gff-nostream/-/gff-nostream-1.3.4.tgz", "integrity": "sha512-+UmB/NcaXAIj+V/jjZWW9NWGAL2cDkcTIIfia/LqAYWURBIWxwVkzC744q2WXB62IVb8DaF+8CWXGLm9EnQqNg==" }, - "node_modules/github-from-package": { - "version": "0.0.0", - "license": "MIT" - }, "node_modules/glob": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", @@ -7751,18 +7574,6 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/hyperdyperid": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", @@ -7872,10 +7683,6 @@ "version": "2.0.4", "license": "ISC" }, - "node_modules/ini": { - "version": "1.3.8", - "license": "ISC" - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -7893,20 +7700,6 @@ "node": ">=10.13.0" } }, - "node_modules/into-stream": { - "version": "6.0.0", - "license": "MIT", - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", @@ -8015,6 +7808,7 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8177,6 +7971,7 @@ }, "node_modules/isexe": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -8298,6 +8093,7 @@ }, "node_modules/jsonfile": { "version": "6.1.0", + "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -8615,16 +8411,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -8666,6 +8452,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8676,15 +8463,9 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.2", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -8694,6 +8475,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", + "dev": true, "dependencies": { "minipass": "^7.0.4", "rimraf": "^5.0.5" @@ -8706,6 +8488,7 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -8725,6 +8508,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -8738,12 +8522,14 @@ "node_modules/minizlib/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true }, "node_modules/minizlib/node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -8759,6 +8545,7 @@ "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, "dependencies": { "glob": "^10.3.7" }, @@ -8773,6 +8560,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, "bin": { "mkdirp": "dist/cjs/src/bin.js" }, @@ -8783,10 +8571,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "license": "MIT" - }, "node_modules/mobx": { "version": "6.13.1", "license": "MIT", @@ -8873,40 +8657,6 @@ "multicast-dns": "cli.js" } }, - "node_modules/multistream": { - "version": "4.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/multistream/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/nanoid": { "version": "3.3.8", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", @@ -8925,10 +8675,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "license": "MIT" - }, "node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", @@ -8952,26 +8698,6 @@ "tslib": "^2.0.3" } }, - "node_modules/node-abi": { - "version": "3.65.0", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.3", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -8984,25 +8710,6 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -9015,7 +8722,9 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" }, "node_modules/node-polyfill-webpack-plugin": { "version": "4.1.0", @@ -9239,13 +8948,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/open": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/open/-/open-10.1.1.tgz", @@ -9277,13 +8979,6 @@ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -9340,6 +9035,7 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.0", + "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/pako": { @@ -9430,6 +9126,7 @@ }, "node_modules/path-key": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9723,30 +9420,6 @@ "dev": true, "license": "MIT" }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/pretty-error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", @@ -9798,14 +9471,6 @@ "version": "2.0.1", "license": "MIT" }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/prop-types": { "version": "15.8.1", "license": "MIT", @@ -9859,14 +9524,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" }, - "node_modules/pump": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9972,26 +9629,6 @@ "quickselect": "^2.0.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -10467,14 +10104,6 @@ "strip-ansi": "^6.0.1" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "license": "MIT", @@ -11033,6 +10662,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -11043,6 +10673,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11076,47 +10707,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/sirv": { "version": "2.0.4", "dev": true, @@ -11307,13 +10897,6 @@ "node": ">= 6" } }, - "node_modules/stream-meter": { - "version": "1.0.4", - "license": "MIT", - "dependencies": { - "readable-stream": "^2.1.4" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "license": "MIT", @@ -11323,6 +10906,7 @@ }, "node_modules/string-width": { "version": "4.2.3", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -11336,6 +10920,7 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -11348,6 +10933,7 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -11359,6 +10945,7 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -11442,6 +11029,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -11454,47 +11042,11 @@ "node": ">=18" } }, - "node_modules/tar-fs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", - "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/tar/node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, "engines": { "node": ">=18" } @@ -11503,6 +11055,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, "engines": { "node": ">=18" } @@ -11625,6 +11178,7 @@ "version": "0.2.12", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, "dependencies": { "fdir": "^6.4.3", "picomatch": "^4.0.2" @@ -11640,6 +11194,7 @@ "version": "6.4.3", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -11653,6 +11208,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, "engines": { "node": ">=12" }, @@ -11711,11 +11267,6 @@ "node": ">=6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/tree-dump": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", @@ -11765,16 +11316,6 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/type-fest": { "version": "4.38.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz", @@ -11873,6 +11414,7 @@ }, "node_modules/universalify": { "version": "2.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -11891,6 +11433,8 @@ "version": "0.12.3", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "dev": true, + "license": "MIT", "dependencies": { "bluebird": "~3.7.2", "duplexer2": "~0.1.4", @@ -12080,11 +11624,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, "node_modules/webpack": { "version": "5.99.7", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.7.tgz", @@ -12441,17 +11980,9 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -12489,25 +12020,10 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -12521,10 +12037,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, "node_modules/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", @@ -12562,14 +12074,6 @@ "node": ">=16" } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -12583,31 +12087,6 @@ "node": ">= 6" } }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/jbrowse/package.json b/jbrowse/package.json index 3807eef04..b8823a270 100644 --- a/jbrowse/package.json +++ b/jbrowse/package.json @@ -6,25 +6,24 @@ "setup": "npm ci", "build": "npm run build-dev", "start": "cross-env NODE_ENV=development webpack serve --config ./config/watch.config.js", - "build-no-pkg": "npm run clean && cross-env NODE_ENV=development webpack --config ./config/dev.config.js --progress --profile", - "build-dev": "npm run build-no-pkg", + "build-dev": "npm run clean && cross-env NODE_ENV=development webpack --config ./config/dev.config.js --progress --profile", "build-prod": "npm run clean && cross-env NODE_ENV=production PROD_SOURCE_MAP=source-map webpack --config ./config/prod.config.js --progress --profile", "clean": "rimraf resources/web/gen && rimraf resources/web/jbrowse/gen && rimraf resources/views/gen", - "prepareCli": "rimraf ./buildCli && rimraf ./resources/external/jb-cli && npm install @jbrowse/cli@1.7.4 --prefix ./buildCli", - "jb-pkg": "npm run prepareCli && npx pkg --outdir=./resources/external/jb-cli ./buildCli/node_modules/@jbrowse/cli && rimraf ./buildCli" + "jb-sea:fetch": "node ./resources/external/fetch-jbrowse-bundle.mjs", + "jb-sea:build": "node ./resources/external/build-sea.mjs ./resources/external/jbrowse.js", + "jb-sea": "npm run jb-sea:fetch && npm run jb-sea:build" }, "dependencies": { "@gmod/vcf": "^6.0.9", "@jbrowse/core": "^3.2.0", - "@jbrowse/product-core": "^3.2.0", "@jbrowse/plugin-linear-genome-view": "^3.2.0", "@jbrowse/plugin-svg": "^3.2.0", "@jbrowse/plugin-variants": "^3.2.0", + "@jbrowse/product-core": "^3.2.0", "@jbrowse/react-linear-genome-view2": "^3.2.0", "@labkey/api": "^1.39.0", "@labkey/components": "^6.32.2", "@mui/x-data-grid": "^7.28.1", - "@yao-pkg/pkg": "^6.3.2", "assert": "^2.1.0", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", @@ -54,6 +53,8 @@ "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", "rimraf": "^6.0.1", - "typescript": "^5.1.6" + "tar": "^7.4.3", + "typescript": "^5.1.6", + "unzipper": "^0.12.3" } } diff --git a/jbrowse/resources/external/build-sea.mjs b/jbrowse/resources/external/build-sea.mjs new file mode 100644 index 000000000..baae7c2f2 --- /dev/null +++ b/jbrowse/resources/external/build-sea.mjs @@ -0,0 +1,193 @@ +// Build SEA for all platforms (win/linux/macos) from any host. +// - Creates sea-prep.blob once from resources/external/jbrowse.js +// - Downloads official Node runtimes for the same Node version as process.execPath +// - Injects the blob into each runtime with postject +// - Writes outputs to resources/external/jb-cli: +// cli-win.exe, cli-linux, cli-macos +// - Cleans up temp files and resources/external/jbrowse.js at the end + +import { execFileSync, execSync } from 'node:child_process'; +import { + copyFileSync, chmodSync, existsSync, mkdirSync, rmSync, renameSync, writeFileSync +} from 'node:fs'; +import { join, resolve } from 'node:path'; +import https from 'node:https'; +import { createWriteStream, createReadStream } from 'node:fs'; +import * as unzipper from 'unzipper'; + +const ROOT = resolve('.'); +const OUTDIR = join(ROOT, 'resources', 'external', 'jb-cli'); +const TMPDIR = join(ROOT, '.sea-tmp'); +const INPUT_JS = join(ROOT, 'resources', 'external', 'jbrowse.js'); + +const NODE_VERSION = process.versions.node; +const DIST_BASE = process.env.NODE_DIST_URL || 'https://nodejs.org/dist'; +const TARGETS = [ + ['win-x64', 'cli-win.exe', 'zip'], + ['linux-x64', 'cli-linux', 'tar.xz'], + ['darwin-x64','cli-macos', 'tar.xz'], + // ['darwin-arm64','cli-macos-arm64','tar.xz'], + // ['linux-arm64','cli-linux-arm64','tar.xz'], +]; + +const SENTINEL = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'; +const POSTJECT_PKG = 'postject@1.0.0-alpha.6'; + +function log(s){ console.log(s); } +function warn(s){ console.warn(s); } +function fail(e){ console.error(e); process.exit(1); } + +function ensureDirs(){ + mkdirSync(OUTDIR, { recursive: true }); + mkdirSync(TMPDIR, { recursive: true }); +} + +function httpDownload(url, dest){ + return new Promise((resolveP, rejectP)=>{ + const file = createWriteStream(dest); + https.get(url, res=>{ + if(res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location){ + httpDownload(res.headers.location, dest).then(resolveP, rejectP); + return; + } + if(res.statusCode !== 200){ + rejectP(new Error(`Download failed ${res.statusCode}: ${url}`)); + return; + } + res.pipe(file); + file.on('finish', ()=>file.close(()=>resolveP(void 0))); + }).on('error', err=>{ rejectP(err); }); + }); +} + +function runOrThrow(cmd, args, opts={}){ + execFileSync(cmd, args, { stdio: 'inherit', ...opts }); +} + +function shellOrThrow(command){ + execSync(command, { stdio: 'inherit', shell: true }); +} + +// postject runner with fallbacks +function runPostject(args){ + const isWin = process.platform === 'win32'; + const npxCmd = isWin ? 'npx.cmd' : 'npx'; + const npmCmd = isWin ? 'npm.cmd' : 'npm'; + try { runOrThrow(npxCmd, ['--yes', POSTJECT_PKG, ...args]); return; } + catch{ warn('[postject] npx failed, trying npm exec…'); } + try { runOrThrow(npmCmd, ['exec', '-y', POSTJECT_PKG, '--', ...args]); return; } + catch{ warn('[postject] npm exec failed, trying shell npx…'); } + try { shellOrThrow(`npx --yes ${POSTJECT_PKG} ${args.map(a=>`"${a}"`).join(' ')}`); return; } + catch{ warn('[postject] shell npx failed, trying shell npm exec…'); } + shellOrThrow(`npm exec -y ${POSTJECT_PKG} -- ${args.map(a=>`"${a}"`).join(' ')}`); +} + +async function extractZip(zipPath, outDir){ + if (process.platform === 'win32') { + try { + shellOrThrow(`powershell -NoProfile -Command "Expand-Archive -Force '${zipPath.replace(/'/g, "''")}' '${outDir.replace(/'/g, "''")}'"`); + return; + } catch (e) { + // Fall through to unzipper if PowerShell isn’t present or fails + } + } else { + // POSIX: try `unzip` if present + try { + shellOrThrow(`unzip -o "${zipPath}" -d "${outDir}"`); + return; + } catch (e) { + // Fall through to unzipper + } + } + + await new Promise((resolveP, rejectP) => { + const stream = createReadStream(zipPath) + .pipe(unzipper.Extract({ path: outDir })); + + stream.on('close', resolveP); + stream.on('error', rejectP); + }); +} + +// extract only bin/node from tar.xz to avoid symlink issues on Windows +function extractNodeFromTarXz(tarxzPath, outDir, target) { + const innerPath = `node-v${NODE_VERSION}-${target}/bin/node`; + try { shellOrThrow(`tar -xJf "${tarxzPath}" -C "${outDir}" "${innerPath}"`); } + catch { shellOrThrow(`bsdtar -xf "${tarxzPath}" -C "${outDir}" "${innerPath}"`); } + return join(outDir, innerPath); +} + +function nodeBinaryPathFromExtract(dir, target){ + const base = `node-v${NODE_VERSION}-${target}`; + if (target.startsWith('win')) return join(dir, base, 'node.exe'); + return join(dir, base, 'bin', 'node'); +} + +function injectForTarget(target, outName, archiveExt, blobPath){ + const distUrl = `${DIST_BASE}/v${NODE_VERSION}/node-v${NODE_VERSION}-${target}.${archiveExt}`; + const dlPath = join(TMPDIR, `node-${target}.${archiveExt}`); + + log(`\n=== Target ${target} ===`); + log(`Downloading: ${distUrl}`); + return httpDownload(distUrl, dlPath).then(async ()=>{ + log('Extracting…'); + let nodePath; + if (archiveExt === 'zip') { + await extractZip(dlPath, TMPDIR); + nodePath = nodeBinaryPathFromExtract(TMPDIR, target); + } else { + nodePath = extractNodeFromTarXz(dlPath, TMPDIR, target); + } + if (!existsSync(nodePath)) fail(`node binary not found in ${nodePath}`); + + const workExe = join(TMPDIR, `work-${outName}`); + copyFileSync(nodePath, workExe); + + const postjectArgs = target.startsWith('darwin') + ? [workExe, 'NODE_SEA_BLOB', blobPath, '--sentinel-fuse', SENTINEL, '--macho-segment-name', 'NODE_SEA'] + : [workExe, 'NODE_SEA_BLOB', blobPath, '--sentinel-fuse', SENTINEL]; + + log('Injecting SEA blob…'); + runPostject(postjectArgs); + + if (!target.startsWith('win')) chmodSync(workExe, 0o755); + + const finalPath = join(OUTDIR, outName); + if (existsSync(finalPath)) rmSync(finalPath, { force: true }); + renameSync(workExe, finalPath); + + rmSync(dlPath, { force: true }); + try { rmSync(join(TMPDIR, `node-v${NODE_VERSION}-${target}`), { recursive: true, force: true }); } catch {} + log(`Wrote ${finalPath}`); + }); +} + +function buildBlobOnce(){ + const cfgPath = join(TMPDIR, 'sea-config.json'); + const blobPath = join(TMPDIR, 'sea-prep.blob'); + log('Creating SEA blob…'); + const cfg = { main: INPUT_JS, output: blobPath, disableExperimentalSEAWarning: true }; + writeFileSync(cfgPath, JSON.stringify(cfg, null, 2)); + runOrThrow(process.execPath, ['--experimental-sea-config', cfgPath]); + return blobPath; +} + +async function main(){ + ensureDirs(); + if (!existsSync(INPUT_JS)) fail(`Missing ${INPUT_JS}. Run your fetch step first.`); + rmSync(TMPDIR, { recursive: true, force: true }); + mkdirSync(TMPDIR, { recursive: true }); + + const blob = buildBlobOnce(); + + for (const [target, outName, ext] of TARGETS) { + await injectForTarget(target, outName, ext, blob); + } + + try { rmSync(TMPDIR, { recursive: true, force: true }); } catch {} + try { if (existsSync(INPUT_JS)) rmSync(INPUT_JS, { force: true }); } catch {} + + log('\nAll targets built.'); +} + +main().catch(fail); diff --git a/jbrowse/resources/external/fetch-jbrowse-bundle.mjs b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs new file mode 100644 index 000000000..04623fe0b --- /dev/null +++ b/jbrowse/resources/external/fetch-jbrowse-bundle.mjs @@ -0,0 +1,57 @@ +import { execSync } from 'node:child_process'; +import { existsSync, mkdirSync, copyFileSync, rmSync } from 'node:fs'; +import { join, resolve } from 'node:path'; + +const ROOT = resolve('.'); +const BUILD = join(ROOT, 'buildCli'); +const OUTDIR = join(ROOT, 'resources', 'external'); +const OUTFILE = join(OUTDIR, 'jbrowse.js'); + +async function extractTgz(tgzPath, cwd) { + try { + const mod = await import('tar').catch(() => null); + const tar = mod?.default ?? mod; + if (tar?.x) { + await tar.x({ file: tgzPath, cwd }); + return; + } + } catch { + } + execSync(`tar -xzf "${tgzPath}" -C "${cwd}"`, { stdio: 'inherit', shell: true }); +} + +async function main() { + if (existsSync(BUILD)) rmSync(BUILD, { recursive: true, force: true }); + mkdirSync(BUILD, { recursive: true }); + mkdirSync(OUTDIR, { recursive: true }); + + console.log('Packing @jbrowse/cli (latest)…'); + const out = execSync('npm pack @jbrowse/cli', { + cwd: BUILD, + stdio: ['ignore', 'pipe', 'inherit'], + shell: true, + }) + .toString() + .trim(); + + const tgz = join(BUILD, out); + console.log(`Downloaded: ${tgz}`); + + console.log('Extracting tarball…'); + await extractTgz(tgz, BUILD); + + const bundled = join(BUILD, 'package', 'bundle', 'index.js'); + if (!existsSync(bundled)) { + throw new Error(`bundle/index.js not found at ${bundled}`); + } + + copyFileSync(bundled, OUTFILE); + console.log(`Copied bundle to ${OUTFILE}`); + + rmSync(BUILD, { recursive: true, force: true }); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/jbrowse/src/org/labkey/jbrowse/JBrowseManager.java b/jbrowse/src/org/labkey/jbrowse/JBrowseManager.java index c1039d844..1db0ab1d3 100644 --- a/jbrowse/src/org/labkey/jbrowse/JBrowseManager.java +++ b/jbrowse/src/org/labkey/jbrowse/JBrowseManager.java @@ -239,7 +239,7 @@ public void testJBrowseCli() throws Exception SimpleScriptWrapper wrapper = new SimpleScriptWrapper(_log); wrapper.setThrowNonZeroExits(false); - String output = wrapper.executeWithOutput(Arrays.asList(exe.getPath(), "help")); + String output = wrapper.executeWithOutput(Arrays.asList(exe.getPath(), "--help")); if (wrapper.getLastReturnCode() != 0) { _log.error("Non-zero exit from testJBrowseCli: " + wrapper.getLastReturnCode()); diff --git a/singlecell/resources/chunks/AppendMetadata.R b/singlecell/resources/chunks/AppendMetadata.R index f14a25f65..d67d25fea 100644 --- a/singlecell/resources/chunks/AppendMetadata.R +++ b/singlecell/resources/chunks/AppendMetadata.R @@ -4,9 +4,16 @@ if (!file.exists(netRc)) { stop(paste0('Unable to find file: ', netRc)) } -invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc)) +invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc, timeout = 60, timeout_ms = 60000, connecttimeout = 20, connecttimeout_ms = 20000)) Rdiscvr::SetLabKeyDefaults(baseUrl = serverBaseUrl, defaultFolder = defaultLabKeyFolder) +curlOpt <- curl::curl_options('timeout') +logger::log_info('Curl options:') +for (x in names(curlOpt)) { + logger::log_info(paste0(x, ': ', curlOpt[x])) +} +rm(curlOpt) + for (datasetId in names(seuratObjects)) { printName(datasetId) seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) diff --git a/singlecell/resources/chunks/ApplyKnownClonotypicData.R b/singlecell/resources/chunks/ApplyKnownClonotypicData.R new file mode 100644 index 000000000..d73e4ef1e --- /dev/null +++ b/singlecell/resources/chunks/ApplyKnownClonotypicData.R @@ -0,0 +1,20 @@ +netRc <- paste0(Sys.getenv('USER_HOME'), '/.netrc') +if (!file.exists(netRc)) { + print(list.files(Sys.getenv('USER_HOME'))) + stop(paste0('Unable to find file: ', netRc)) +} + +invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc)) +Rdiscvr::SetLabKeyDefaults(baseUrl = serverBaseUrl, defaultFolder = defaultLabKeyFolder) + +for (datasetId in names(seuratObjects)) { + printName(datasetId) + seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) + + seuratObj <- ApplyKnownClonotypicData(seuratObj) + saveData(seuratObj, datasetId) + + # Cleanup + rm(seuratObj) + gc() +} \ No newline at end of file diff --git a/singlecell/resources/chunks/CalculateTcrRepertoireStats.R b/singlecell/resources/chunks/CalculateTcrRepertoireStats.R new file mode 100644 index 000000000..a365c1bcb --- /dev/null +++ b/singlecell/resources/chunks/CalculateTcrRepertoireStats.R @@ -0,0 +1,21 @@ +netRc <- paste0(Sys.getenv('USER_HOME'), '/.netrc') +if (!file.exists(netRc)) { + print(list.files(Sys.getenv('USER_HOME'))) + stop(paste0('Unable to find file: ', netRc)) +} + +invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc)) +Rdiscvr::SetLabKeyDefaults(baseUrl = serverBaseUrl, defaultFolder = defaultLabKeyFolder) + +for (datasetId in names(seuratObjects)) { + printName(datasetId) + seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) + + outputFile <- gsub(seuratObjects[[datasetId]], pattern = '.rds', replacement = '.tcrStats.txt') + df <- Rdiscvr::CalculateAndStoreTcrRepertoireStats(seuratObj, outputFile = outputFile) + + # Cleanup + rm(seuratObj) + rm(df) + gc() +} \ No newline at end of file diff --git a/singlecell/resources/chunks/PredictTcellActivation.R b/singlecell/resources/chunks/PredictTcellActivation.R new file mode 100644 index 000000000..7b18f1922 --- /dev/null +++ b/singlecell/resources/chunks/PredictTcellActivation.R @@ -0,0 +1,12 @@ +for (datasetId in names(seuratObjects)) { + printName(datasetId) + seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) + + seuratObj <- RIRA::PredictTcellActivation(seuratObj) + + saveData(seuratObj, datasetId) + + # Cleanup + rm(seuratObj) + gc() +} \ No newline at end of file diff --git a/singlecell/resources/chunks/StudyMetadata.R b/singlecell/resources/chunks/StudyMetadata.R index b64a2c66e..f5fb694ff 100644 --- a/singlecell/resources/chunks/StudyMetadata.R +++ b/singlecell/resources/chunks/StudyMetadata.R @@ -4,9 +4,16 @@ if (!file.exists(netRc)) { stop(paste0('Unable to find file: ', netRc)) } -invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc)) +invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc, timeout = 60, timeout_ms = 60000, connecttimeout = 20, connecttimeout_ms = 20000)) Rdiscvr::SetLabKeyDefaults(baseUrl = serverBaseUrl, defaultFolder = defaultLabKeyFolder) +curlOpt <- curl::curl_options('timeout') +logger::log_info('Curl options:') +for (x in names(curlOpt)) { + logger::log_info(paste0(x, ': ', curlOpt[x])) +} +rm(curlOpt) + for (datasetId in names(seuratObjects)) { printName(datasetId) seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) diff --git a/singlecell/resources/chunks/UpdateSeuratPrototype.R b/singlecell/resources/chunks/UpdateSeuratPrototype.R index a30396d81..f5b41a24b 100644 --- a/singlecell/resources/chunks/UpdateSeuratPrototype.R +++ b/singlecell/resources/chunks/UpdateSeuratPrototype.R @@ -7,6 +7,12 @@ if (!file.exists(netRc)) { invisible(Rlabkey::labkey.setCurlOptions(NETRC_FILE = netRc)) Rdiscvr::SetLabKeyDefaults(baseUrl = serverBaseUrl, defaultFolder = defaultLabKeyFolder) +if (Sys.getenv('SEURAT_MAX_THREADS') != '') { + nCores <- Sys.getenv('SEURAT_MAX_THREADS') +} else { + nCores <- 1 +} + for (datasetId in names(seuratObjects)) { printName(datasetId) seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) @@ -34,6 +40,20 @@ for (datasetId in names(seuratObjects)) { seuratObj <- Rdiscvr::ClassifyTNKByExpression(seuratObj) } + if (saveRepertoireStats) { + seuratObj <- readSeuratRDS(seuratObjects[[datasetId]]) + outputFile <- gsub(seuratObjects[[datasetId]], pattern = '.rds', replacement = '.tcrStats.txt') + df <- Rdiscvr::CalculateAndStoreTcrRepertoireStats(seuratObj, outputFile = outputFile) + } + + if (scoreActivation) { + seuratObj <- RIRA::PredictTcellActivation(seuratObj) + } + + if (recalculateUCells) { + seuratObj <- RIRA::CalculateUCellScores(seuratObj, storeRanks = FALSE, assayName = 'RNA', forceRecalculate = TRUE, ncores = nCores) + } + saveData(seuratObj, datasetId) # Cleanup diff --git a/singlecell/src/org/labkey/singlecell/SingleCellModule.java b/singlecell/src/org/labkey/singlecell/SingleCellModule.java index 5559f897f..def91fcd7 100644 --- a/singlecell/src/org/labkey/singlecell/SingleCellModule.java +++ b/singlecell/src/org/labkey/singlecell/SingleCellModule.java @@ -42,8 +42,10 @@ import org.labkey.singlecell.pipeline.singlecell.AppendNimble; import org.labkey.singlecell.pipeline.singlecell.AppendSaturation; import org.labkey.singlecell.pipeline.singlecell.AppendTcr; +import org.labkey.singlecell.pipeline.singlecell.ApplyKnownClonotypicData; import org.labkey.singlecell.pipeline.singlecell.AvgExpression; import org.labkey.singlecell.pipeline.singlecell.CalculateGeneComponentScores; +import org.labkey.singlecell.pipeline.singlecell.CalculateTcrRepertoireStats; import org.labkey.singlecell.pipeline.singlecell.CalculateUCellScores; import org.labkey.singlecell.pipeline.singlecell.CellBarcodeFilter; import org.labkey.singlecell.pipeline.singlecell.CheckExpectations; @@ -77,6 +79,7 @@ import org.labkey.singlecell.pipeline.singlecell.PlotAssayFeatures; import org.labkey.singlecell.pipeline.singlecell.PlotAverageCiteSeqCounts; import org.labkey.singlecell.pipeline.singlecell.PredictScTour; +import org.labkey.singlecell.pipeline.singlecell.PredictTcellActivation; import org.labkey.singlecell.pipeline.singlecell.PrepareRawCounts; import org.labkey.singlecell.pipeline.singlecell.RemoveCellCycle; import org.labkey.singlecell.pipeline.singlecell.RunCellHashing; @@ -299,6 +302,9 @@ public static void registerPipelineSteps() SequencePipelineService.get().registerPipelineStep(new PerformDefaultNimbleAppend.Provider()); SequencePipelineService.get().registerPipelineStep(new PerformMhcDimRedux.Provider()); SequencePipelineService.get().registerPipelineStep(new RunTricycle.Provider()); + SequencePipelineService.get().registerPipelineStep(new ApplyKnownClonotypicData.Provider()); + SequencePipelineService.get().registerPipelineStep(new CalculateTcrRepertoireStats.Provider()); + SequencePipelineService.get().registerPipelineStep(new PredictTcellActivation.Provider()); SequenceAnalysisService.get().registerReadsetListener(new SingleCellReadsetListener()); } diff --git a/singlecell/src/org/labkey/singlecell/pipeline/singlecell/ApplyKnownClonotypicData.java b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/ApplyKnownClonotypicData.java new file mode 100644 index 000000000..1f6dbf45b --- /dev/null +++ b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/ApplyKnownClonotypicData.java @@ -0,0 +1,39 @@ +package org.labkey.singlecell.pipeline.singlecell; + +import org.labkey.api.sequenceanalysis.pipeline.AbstractPipelineStepProvider; +import org.labkey.api.sequenceanalysis.pipeline.PipelineContext; +import org.labkey.api.singlecell.pipeline.SingleCellStep; + +import java.util.List; + +public class ApplyKnownClonotypicData extends AbstractRDiscvrStep +{ + public ApplyKnownClonotypicData(PipelineContext ctx, ApplyKnownClonotypicData.Provider provider) + { + super(provider, ctx); + } + + public static class Provider extends AbstractPipelineStepProvider + { + public Provider() + { + super("ApplyKnownClonotypicData", "Append Known Clonotype/Antigen Data", "RDiscvr", "This will query the clone_responses table and append a column tagging each cell for matching antigens (based on clonotype)", List.of( + + ), null, null); + } + + + @Override + public ApplyKnownClonotypicData create(PipelineContext ctx) + { + return new ApplyKnownClonotypicData(ctx, this); + } + } + + @Override + public String getFileSuffix() + { + return "ctd"; + } +} + diff --git a/singlecell/src/org/labkey/singlecell/pipeline/singlecell/CalculateTcrRepertoireStats.java b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/CalculateTcrRepertoireStats.java new file mode 100644 index 000000000..e802c342a --- /dev/null +++ b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/CalculateTcrRepertoireStats.java @@ -0,0 +1,43 @@ +package org.labkey.singlecell.pipeline.singlecell; + +import org.labkey.api.sequenceanalysis.pipeline.AbstractPipelineStepProvider; +import org.labkey.api.sequenceanalysis.pipeline.PipelineContext; +import org.labkey.api.singlecell.pipeline.SingleCellStep; + +import java.util.Arrays; + +public class CalculateTcrRepertoireStats extends AbstractRDiscvrStep +{ + public CalculateTcrRepertoireStats(PipelineContext ctx, CalculateTcrRepertoireStats.Provider provider) + { + super(provider, ctx); + } + + public static class Provider extends AbstractPipelineStepProvider + { + public Provider() + { + super("CalculateTcrRepertoireStats", "Calculate TCR Repertoire Stats", "CellMembrane/tcrdist3", "This will calculate TCR diversity metrics, and save the results in the database.", Arrays.asList( + + ), null, null); + } + + @Override + public CalculateTcrRepertoireStats create(PipelineContext ctx) + { + return new CalculateTcrRepertoireStats(ctx, this); + } + } + + @Override + public boolean createsSeuratObjects() + { + return false; + } + + @Override + public String getFileSuffix() + { + return "ts"; + } +} diff --git a/singlecell/src/org/labkey/singlecell/pipeline/singlecell/PredictTcellActivation.java b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/PredictTcellActivation.java new file mode 100644 index 000000000..f4e9fdf83 --- /dev/null +++ b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/PredictTcellActivation.java @@ -0,0 +1,37 @@ +package org.labkey.singlecell.pipeline.singlecell; + +import org.labkey.api.sequenceanalysis.pipeline.AbstractPipelineStepProvider; +import org.labkey.api.sequenceanalysis.pipeline.PipelineContext; +import org.labkey.api.singlecell.pipeline.SingleCellStep; + +import java.util.List; + +public class PredictTcellActivation extends AbstractRDiscvrStep +{ + public PredictTcellActivation(PipelineContext ctx, PredictTcellActivation.Provider provider) + { + super(provider, ctx); + } + + public static class Provider extends AbstractPipelineStepProvider + { + public Provider() + { + super("PredictTcellActivation", "Predict T cell Activation", "RIRA", "This uses RIRA::PredictTcellActivation to predict TCR-triggered T cells", List.of(), null, null); + } + + + @Override + public PredictTcellActivation create(PipelineContext ctx) + { + return new PredictTcellActivation(ctx, this); + } + } + + @Override + public String getFileSuffix() + { + return "tca"; + } +} + diff --git a/singlecell/src/org/labkey/singlecell/pipeline/singlecell/UpdateSeuratPrototype.java b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/UpdateSeuratPrototype.java index 9a9329b96..fad042f96 100644 --- a/singlecell/src/org/labkey/singlecell/pipeline/singlecell/UpdateSeuratPrototype.java +++ b/singlecell/src/org/labkey/singlecell/pipeline/singlecell/UpdateSeuratPrototype.java @@ -48,6 +48,18 @@ public Provider() {{ put("checked", false); }}, false), + SeuratToolParameter.create("recalculateUCells", "Recalculate UCells", "If checked, RIRA::CalculateUCellScores will be re-run", "checkbox", new JSONObject() + {{ + put("checked", true); + }}, true), + SeuratToolParameter.create("saveRepertoireStats", "Save TCR Repertoire Stats", "If checked, Rdiscvr::CalculateAndStoreTcrRepertoireStats will be run", "checkbox", new JSONObject() + {{ + put("checked", true); + }}, true), + SeuratToolParameter.create("scoreActivation", "Score T Cell Activation", "If checked, RIRA::PredictTcellActivation will be run", "checkbox", new JSONObject() + {{ + put("checked", true); + }}, true), SeuratToolParameter.create("keepOriginal", "Keep Copy of Original File", "If checked, the original file will be copied with the file extension '.bk'", "checkbox", new JSONObject() {{ put("checked", false);