@apollo-annotation/cli 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +374 -135
- package/bin/dev.js +2 -2
- package/bin/run.js +2 -2
- package/dist/ApolloConf.js +1 -0
- package/dist/baseCommand.d.ts +1 -1
- package/dist/baseCommand.js +7 -7
- package/dist/commands/assembly/add-from-fasta.d.ts +23 -0
- package/dist/commands/assembly/add-from-fasta.js +165 -0
- package/dist/commands/assembly/{add-gff.d.ts → add-from-gff.d.ts} +5 -3
- package/dist/commands/assembly/{add-gff.js → add-from-gff.js} +20 -22
- package/dist/commands/assembly/check.js +9 -9
- package/dist/commands/assembly/delete.js +4 -4
- package/dist/commands/assembly/get.js +4 -4
- package/dist/commands/assembly/get.test.js +3 -3
- package/dist/commands/assembly/sequence.js +8 -14
- package/dist/commands/change/get.js +7 -7
- package/dist/commands/change/get.test.js +1 -1
- package/dist/commands/config.js +4 -5
- package/dist/commands/feature/add-child.js +18 -19
- package/dist/commands/feature/check.js +11 -11
- package/dist/commands/feature/copy.js +12 -14
- package/dist/commands/feature/delete.js +13 -19
- package/dist/commands/feature/edit-attribute.js +18 -11
- package/dist/commands/feature/edit-coords.js +36 -21
- package/dist/commands/feature/edit-type.js +7 -11
- package/dist/commands/feature/edit.js +5 -6
- package/dist/commands/feature/get-id.js +5 -6
- package/dist/commands/feature/get.js +3 -4
- package/dist/commands/feature/import.d.ts +2 -2
- package/dist/commands/feature/import.js +26 -39
- package/dist/commands/feature/search.js +7 -7
- package/dist/commands/file/delete.d.ts +13 -0
- package/dist/commands/file/delete.js +58 -0
- package/dist/commands/file/download.d.ts +14 -0
- package/dist/commands/file/download.js +45 -0
- package/dist/commands/file/get.d.ts +13 -0
- package/dist/commands/file/get.js +38 -0
- package/dist/commands/file/upload.d.ts +16 -0
- package/dist/commands/file/upload.js +88 -0
- package/dist/commands/jbrowse/get-config.d.ts +10 -0
- package/dist/commands/jbrowse/get-config.js +21 -0
- package/dist/commands/jbrowse/set-config.d.ts +13 -0
- package/dist/commands/jbrowse/set-config.js +51 -0
- package/dist/commands/login.js +12 -16
- package/dist/commands/logout.js +3 -3
- package/dist/commands/{assembly/add-fasta.d.ts → refseq/add-alias.d.ts} +3 -4
- package/dist/commands/refseq/add-alias.js +72 -0
- package/dist/commands/refseq/get.js +8 -8
- package/dist/commands/status.js +5 -4
- package/dist/commands/user/get.js +3 -3
- package/dist/commands/user/get.test.js +1 -1
- package/dist/fileCommand.d.ts +5 -0
- package/dist/fileCommand.js +76 -0
- package/dist/test/fixtures.js +2 -2
- package/dist/utils.d.ts +20 -9
- package/dist/utils.js +33 -80
- package/oclif.manifest.json +495 -58
- package/package.json +56 -42
- package/dist/commands/assembly/add-fasta.js +0 -88
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { Agent, fetch } from 'undici';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
5
|
+
import { createFetchErrorMessage, localhostToAddress, queryApollo, } from '../../utils.js';
|
|
6
|
+
import { ConfigError } from '../../ApolloConf.js';
|
|
7
|
+
export default class AddRefNameAlias extends BaseCommand {
|
|
8
|
+
static summary = 'Add reference name aliases from a file';
|
|
9
|
+
static description = 'Reference name aliasing is a process to make chromosomes that are named slightly differently but which refer to the same thing render properly. This command reads a file with reference name aliases and adds them to the database.';
|
|
10
|
+
static examples = [
|
|
11
|
+
{
|
|
12
|
+
description: 'Add reference name aliases:',
|
|
13
|
+
command: '<%= config.bin %> <%= command.id %> -i alias.txt -a myAssembly',
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
'input-file': Flags.string({
|
|
18
|
+
char: 'i',
|
|
19
|
+
description: 'Input refname alias file',
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
assembly: Flags.string({
|
|
23
|
+
char: 'a',
|
|
24
|
+
description: 'Name for this assembly.',
|
|
25
|
+
required: true,
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
async run() {
|
|
29
|
+
const { flags } = await this.parse(AddRefNameAlias);
|
|
30
|
+
if (!fs.existsSync(flags['input-file'])) {
|
|
31
|
+
this.error(`File ${flags['input-file']} does not exist`);
|
|
32
|
+
}
|
|
33
|
+
const access = await this.getAccess();
|
|
34
|
+
const filehandle = await fs.promises.open(flags['input-file']);
|
|
35
|
+
const fileContent = await filehandle.readFile({ encoding: 'utf8' });
|
|
36
|
+
await filehandle.close();
|
|
37
|
+
const lines = fileContent.split('\n');
|
|
38
|
+
const refNameAliases = [];
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
const [refName, ...aliases] = line.split('\t');
|
|
41
|
+
refNameAliases.push({ refName, aliases });
|
|
42
|
+
}
|
|
43
|
+
const assemblies = await queryApollo(access.address, access.accessToken, 'assemblies');
|
|
44
|
+
const json = (await assemblies.json());
|
|
45
|
+
const assembly = json.find((x) => 'name' in x && x.name === flags.assembly);
|
|
46
|
+
const assemblyId = assembly && '_id' in assembly ? assembly._id : undefined;
|
|
47
|
+
if (!assemblyId) {
|
|
48
|
+
this.error(`Assembly ${flags.assembly} not found`);
|
|
49
|
+
}
|
|
50
|
+
const change = {
|
|
51
|
+
typeName: 'AddRefSeqAliasesChange',
|
|
52
|
+
assembly: assemblyId,
|
|
53
|
+
refSeqAliases: refNameAliases,
|
|
54
|
+
};
|
|
55
|
+
const auth = {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
body: JSON.stringify(change),
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${access.accessToken}`,
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
63
|
+
};
|
|
64
|
+
const url = new URL(localhostToAddress(`${access.address}/changes`));
|
|
65
|
+
const response = await fetch(url, auth);
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
const errorMessage = await createFetchErrorMessage(response, 'Failed to add reference name aliases');
|
|
68
|
+
throw new ConfigError(errorMessage);
|
|
69
|
+
}
|
|
70
|
+
this.log(`Reference name aliases added successfully to assembly ${flags.assembly}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../baseCommand.js';
|
|
3
|
-
import { convertAssemblyNameToId, idReader, queryApollo
|
|
3
|
+
import { convertAssemblyNameToId, idReader, queryApollo } from '../../utils.js';
|
|
4
4
|
export default class Get extends BaseCommand {
|
|
5
5
|
static summary = 'Get reference sequences';
|
|
6
|
-
static description =
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
static description = 'Output the reference sequences in one or more assemblies in json format. \
|
|
7
|
+
This command returns the sequence characteristics (e.g., name, ID, etc), not the DNA sequences. \
|
|
8
|
+
Use `assembly sequence` for that.';
|
|
9
9
|
static examples = [
|
|
10
10
|
{
|
|
11
|
-
description:
|
|
11
|
+
description: 'All sequences in the database:',
|
|
12
12
|
command: '<%= config.bin %> <%= command.id %>',
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
|
-
description:
|
|
15
|
+
description: 'Only sequences for these assemblies:',
|
|
16
16
|
command: '<%= config.bin %> <%= command.id %> -a mm9 mm10',
|
|
17
17
|
},
|
|
18
18
|
];
|
|
@@ -25,13 +25,13 @@ export default class Get extends BaseCommand {
|
|
|
25
25
|
};
|
|
26
26
|
async run() {
|
|
27
27
|
const { flags } = await this.parse(Get);
|
|
28
|
-
const access = await this.getAccess(
|
|
28
|
+
const access = await this.getAccess();
|
|
29
29
|
const refSeqs = await queryApollo(access.address, access.accessToken, 'refSeqs');
|
|
30
30
|
const json = (await refSeqs.json());
|
|
31
31
|
let keep = json;
|
|
32
32
|
if (flags.assembly !== undefined) {
|
|
33
33
|
keep = [];
|
|
34
|
-
const assembly = idReader(flags.assembly);
|
|
34
|
+
const assembly = await idReader(flags.assembly);
|
|
35
35
|
const assemblyIds = await convertAssemblyNameToId(access.address, access.accessToken, assembly);
|
|
36
36
|
for (const x of json) {
|
|
37
37
|
if (assemblyIds.includes(x['assembly'])) {
|
package/dist/commands/status.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ApolloConf, KEYS } from '../ApolloConf.js';
|
|
4
4
|
import { BaseCommand } from '../baseCommand.js';
|
|
5
|
-
import { basicCheckConfig
|
|
5
|
+
import { basicCheckConfig } from '../utils.js';
|
|
6
6
|
export default class Status extends BaseCommand {
|
|
7
7
|
static summary = 'View authentication status';
|
|
8
|
-
static description =
|
|
9
|
-
|
|
8
|
+
static description = 'This command returns "<profile>: Logged in" if the selected profile \
|
|
9
|
+
has an access token and "<profile>: Logged out" otherwise.\
|
|
10
|
+
Note that this command does not check the validity of the access token.';
|
|
10
11
|
async run() {
|
|
11
12
|
const { flags } = await this.parse(Status);
|
|
12
13
|
let profileName = flags.profile;
|
|
@@ -15,7 +16,7 @@ export default class Status extends BaseCommand {
|
|
|
15
16
|
}
|
|
16
17
|
let configFile = flags['config-file'];
|
|
17
18
|
if (configFile === undefined) {
|
|
18
|
-
configFile = path.join(this.config.configDir, 'config.
|
|
19
|
+
configFile = path.join(this.config.configDir, 'config.yml');
|
|
19
20
|
}
|
|
20
21
|
basicCheckConfig(configFile, profileName);
|
|
21
22
|
const config = new ApolloConf(configFile);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import { BaseCommand } from '../../baseCommand.js';
|
|
3
|
-
import { queryApollo
|
|
3
|
+
import { queryApollo } from '../../utils.js';
|
|
4
4
|
export default class Get extends BaseCommand {
|
|
5
5
|
static summary = 'Get list of users';
|
|
6
|
-
static description =
|
|
6
|
+
static description = 'If set, filters username and role must be both satisfied to return an entry';
|
|
7
7
|
static examples = [
|
|
8
8
|
{
|
|
9
9
|
description: 'By username:',
|
|
@@ -30,7 +30,7 @@ export default class Get extends BaseCommand {
|
|
|
30
30
|
};
|
|
31
31
|
async run() {
|
|
32
32
|
const { flags } = await this.parse(Get);
|
|
33
|
-
const access = await this.getAccess(
|
|
33
|
+
const access = await this.getAccess();
|
|
34
34
|
const users = await queryApollo(access.address, access.accessToken, 'users');
|
|
35
35
|
const json = (await users.json());
|
|
36
36
|
const out = [];
|
|
@@ -7,7 +7,7 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
|
7
7
|
// TODO: Need valid token
|
|
8
8
|
describe.skip('apollo user get: Get users as YAML string', () => {
|
|
9
9
|
before(() => {
|
|
10
|
-
copyFile(`${TEST_DATA_DIR}/complete_config.
|
|
10
|
+
copyFile(`${TEST_DATA_DIR}/complete_config.yml`, CONFIG_FILE, VERBOSE);
|
|
11
11
|
});
|
|
12
12
|
after(() => {
|
|
13
13
|
fs.rmSync(CONFIG_FILE);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { BaseCommand } from './baseCommand.js';
|
|
2
|
+
export declare abstract class FileCommand extends BaseCommand<typeof FileCommand> {
|
|
3
|
+
init(): Promise<void>;
|
|
4
|
+
uploadFile(address: string, accessToken: string, file: string, type: string, isGzip: boolean): Promise<string>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { Transform, pipeline, } from 'node:stream';
|
|
4
|
+
import { SingleBar } from 'cli-progress';
|
|
5
|
+
import { Agent, fetch } from 'undici';
|
|
6
|
+
import { ConfigError } from './ApolloConf.js';
|
|
7
|
+
import { BaseCommand } from './baseCommand.js';
|
|
8
|
+
import { createFetchErrorMessage, localhostToAddress } from './utils.js';
|
|
9
|
+
class ProgressTransform extends Transform {
|
|
10
|
+
size = 0;
|
|
11
|
+
progressBar;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
super(opts);
|
|
14
|
+
this.progressBar = opts.progressBar;
|
|
15
|
+
}
|
|
16
|
+
_transform(chunk, _encoding, callback) {
|
|
17
|
+
this.size += chunk.length;
|
|
18
|
+
this.progressBar.update(this.size);
|
|
19
|
+
callback(null, chunk);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class FileCommand extends BaseCommand {
|
|
23
|
+
async init() {
|
|
24
|
+
await super.init();
|
|
25
|
+
}
|
|
26
|
+
async uploadFile(address, accessToken, file, type, isGzip) {
|
|
27
|
+
const filehandle = await fs.promises.open(file);
|
|
28
|
+
const { size } = await filehandle.stat();
|
|
29
|
+
const stream = filehandle.createReadStream();
|
|
30
|
+
const progressBar = new SingleBar({ etaBuffer: 100_000_000 });
|
|
31
|
+
const progressTransform = new ProgressTransform({ progressBar });
|
|
32
|
+
const body = pipeline(stream, progressTransform, (error) => {
|
|
33
|
+
if (error) {
|
|
34
|
+
progressBar.stop();
|
|
35
|
+
console.error('Error processing file.', error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const headers = new Headers({
|
|
40
|
+
Authorization: `Bearer ${accessToken}`,
|
|
41
|
+
'Content-Type': type,
|
|
42
|
+
'Content-Length': String(size),
|
|
43
|
+
});
|
|
44
|
+
if (isGzip) {
|
|
45
|
+
headers.append('Content-Encoding', 'gzip');
|
|
46
|
+
}
|
|
47
|
+
const init = {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
body,
|
|
50
|
+
duplex: 'half',
|
|
51
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
52
|
+
headers,
|
|
53
|
+
};
|
|
54
|
+
const fileName = path.basename(file);
|
|
55
|
+
const url = new URL(localhostToAddress(`${address}/files`));
|
|
56
|
+
url.searchParams.set('name', fileName);
|
|
57
|
+
url.searchParams.set('type', type);
|
|
58
|
+
progressBar.start(size, 0);
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(url, init);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const errorMessage = await createFetchErrorMessage(response, 'uploadFile failed');
|
|
63
|
+
throw new ConfigError(errorMessage);
|
|
64
|
+
}
|
|
65
|
+
const json = (await response.json());
|
|
66
|
+
return json['_id'];
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error(error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
progressBar.stop();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
package/dist/test/fixtures.js
CHANGED
|
@@ -4,8 +4,8 @@ import path from 'node:path';
|
|
|
4
4
|
export const TEST_DATA_DIR = path.resolve('test_data');
|
|
5
5
|
export const VERBOSE = false;
|
|
6
6
|
export const CONFIG_DIR = path.join(os.homedir(), '.config', 'apollo-cli');
|
|
7
|
-
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.
|
|
8
|
-
const CONFIG_BAK = path.join(TEST_DATA_DIR, 'original.config.
|
|
7
|
+
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.yml');
|
|
8
|
+
const CONFIG_BAK = path.join(TEST_DATA_DIR, 'original.config.yml.bak');
|
|
9
9
|
function renameFile(src, dest, verbose = true) {
|
|
10
10
|
if (fs.existsSync(dest)) {
|
|
11
11
|
throw new Error(`File ${dest} already exists`);
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
2
|
import { Response } from 'undici';
|
|
3
3
|
import { ApolloConf } from './ApolloConf.js';
|
|
4
|
+
import { ApolloAssemblySnapshot } from '@apollo-annotation/mst';
|
|
4
5
|
export declare const CLI_SERVER_ADDRESS = "http://127.0.0.1:5657";
|
|
5
6
|
export declare const CLI_SERVER_ADDRESS_CALLBACK = "http://127.0.0.1:5657/auth/callback";
|
|
6
7
|
export declare class CheckError extends Error {
|
|
@@ -17,27 +18,38 @@ export declare function basicCheckConfig(configFile: string, profileName: string
|
|
|
17
18
|
*/
|
|
18
19
|
export declare function localhostToAddress(url: string): string;
|
|
19
20
|
export declare function deleteAssembly(address: string, accessToken: string, assemblyId: string): Promise<void>;
|
|
20
|
-
export declare function getAssembly(address: string, accessToken: string, assemblyNameOrId: string): Promise<
|
|
21
|
+
export declare function getAssembly(address: string, accessToken: string, assemblyNameOrId: string): Promise<ApolloAssemblySnapshot>;
|
|
21
22
|
export declare function getRefseqId(address: string, accessToken: string, refseqNameOrId?: string, inAssemblyNameOrId?: string): Promise<string[]>;
|
|
22
23
|
export declare function convertCheckNameToId(address: string, accessToken: string, namesOrIds: string[]): Promise<string[]>;
|
|
23
|
-
export declare function assemblyNameToIdDict(address: string, accessToken: string): Promise<Record<string, string>>;
|
|
24
|
+
export declare function assemblyNameToIdDict(address: string, accessToken: string): Promise<Record<string, string | undefined>>;
|
|
24
25
|
/** In input array namesOrIds, substitute common names with internal IDs */
|
|
25
26
|
export declare function convertAssemblyNameToId(address: string, accessToken: string, namesOrIds: string[], verbose?: boolean, removeDuplicates?: boolean): Promise<string[]>;
|
|
26
27
|
export declare function getFeatureById(address: string, accessToken: string, id: string): Promise<Response>;
|
|
27
28
|
export declare function getAssemblyFromRefseq(address: string, accessToken: string, refSeq: string): Promise<string>;
|
|
28
29
|
export declare function queryApollo(address: string, accessToken: string, endpoint: string): Promise<Response>;
|
|
29
30
|
export declare function filterJsonList(json: object[], keep: string[], key: string): object[];
|
|
30
|
-
export declare const getUserCredentials: () => UserCredentials | null;
|
|
31
31
|
export declare const generatePkceChallenge: () => {
|
|
32
32
|
state: string;
|
|
33
33
|
codeVerifier: string;
|
|
34
34
|
codeChallenge: string;
|
|
35
35
|
};
|
|
36
36
|
export declare const waitFor: <T>(eventName: string, emitter: EventEmitter) => Promise<T>;
|
|
37
|
-
interface
|
|
37
|
+
interface bodyFastaFile {
|
|
38
38
|
assemblyName: string;
|
|
39
39
|
typeName: string;
|
|
40
|
-
|
|
40
|
+
fileIds: {
|
|
41
|
+
fa: string;
|
|
42
|
+
};
|
|
43
|
+
assembly: string;
|
|
44
|
+
}
|
|
45
|
+
interface bodyIndexedFiles {
|
|
46
|
+
assemblyName: string;
|
|
47
|
+
typeName: string;
|
|
48
|
+
fileIds: {
|
|
49
|
+
fa: string;
|
|
50
|
+
fai: string;
|
|
51
|
+
gzi: string;
|
|
52
|
+
};
|
|
41
53
|
}
|
|
42
54
|
interface bodyExternalFile {
|
|
43
55
|
assemblyName: string;
|
|
@@ -47,8 +59,7 @@ interface bodyExternalFile {
|
|
|
47
59
|
fai: string;
|
|
48
60
|
};
|
|
49
61
|
}
|
|
50
|
-
export declare function submitAssembly(address: string, accessToken: string, body:
|
|
51
|
-
export declare function
|
|
52
|
-
export declare function
|
|
53
|
-
export declare function idReader(input: string[], removeDuplicates?: boolean): string[];
|
|
62
|
+
export declare function submitAssembly(address: string, accessToken: string, body: bodyFastaFile | bodyExternalFile | bodyIndexedFiles, force: boolean): Promise<object>;
|
|
63
|
+
export declare function readStdin(): Promise<string>;
|
|
64
|
+
export declare function idReader(input: string[], removeDuplicates?: boolean): Promise<string[]>;
|
|
54
65
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
5
|
-
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
6
1
|
import * as crypto from 'node:crypto';
|
|
7
2
|
import * as fs from 'node:fs';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { Agent, FormData, Response, fetch } from 'undici';
|
|
3
|
+
import { stdin, stderr } from 'node:process';
|
|
4
|
+
import { Agent, fetch } from 'undici';
|
|
11
5
|
import { ApolloConf, ConfigError } from './ApolloConf.js';
|
|
12
|
-
const CONFIG_PATH = path.resolve(os.homedir(), '.clirc');
|
|
13
6
|
export const CLI_SERVER_ADDRESS = 'http://127.0.0.1:5657';
|
|
14
7
|
export const CLI_SERVER_ADDRESS_CALLBACK = `${CLI_SERVER_ADDRESS}/auth/callback`;
|
|
15
8
|
export class CheckError extends Error {
|
|
@@ -61,6 +54,7 @@ export async function deleteAssembly(address, accessToken, assemblyId) {
|
|
|
61
54
|
Authorization: `Bearer ${accessToken}`,
|
|
62
55
|
'Content-Type': 'application/json',
|
|
63
56
|
},
|
|
57
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
64
58
|
};
|
|
65
59
|
const url = new URL(localhostToAddress(`${address}/changes`));
|
|
66
60
|
const response = await fetch(url, auth);
|
|
@@ -72,18 +66,16 @@ export async function deleteAssembly(address, accessToken, assemblyId) {
|
|
|
72
66
|
export async function getAssembly(address, accessToken, assemblyNameOrId) {
|
|
73
67
|
const assemblyId = await convertAssemblyNameToId(address, accessToken, [assemblyNameOrId]);
|
|
74
68
|
if (assemblyId.length === 0) {
|
|
75
|
-
|
|
69
|
+
throw new Error(`Assembly "${assemblyNameOrId}" not found`);
|
|
76
70
|
}
|
|
77
71
|
const res = await queryApollo(address, accessToken, 'assemblies');
|
|
78
72
|
const assemblies = (await res.json());
|
|
79
|
-
let assemblyObj = {};
|
|
80
73
|
for (const x of assemblies) {
|
|
81
|
-
if (x
|
|
82
|
-
|
|
83
|
-
break;
|
|
74
|
+
if (x._id === assemblyId[0]) {
|
|
75
|
+
return JSON.parse(JSON.stringify(x));
|
|
84
76
|
}
|
|
85
77
|
}
|
|
86
|
-
|
|
78
|
+
throw new Error(`Assembly "${assemblyNameOrId}" not found`);
|
|
87
79
|
}
|
|
88
80
|
export async function getRefseqId(address, accessToken, refseqNameOrId, inAssemblyNameOrId) {
|
|
89
81
|
if (refseqNameOrId === undefined && inAssemblyNameOrId === undefined) {
|
|
@@ -128,11 +120,11 @@ export async function getRefseqId(address, accessToken, refseqNameOrId, inAssemb
|
|
|
128
120
|
}
|
|
129
121
|
async function checkNameToIdDict(address, accessToken) {
|
|
130
122
|
const asm = await queryApollo(address, accessToken, 'checks/types');
|
|
131
|
-
const ja = (await asm.json());
|
|
123
|
+
const ja = (await asm.json()); // Not sure if CheckResultSnapshot is the right interface
|
|
132
124
|
const nameToId = {};
|
|
133
125
|
for (const x of ja) {
|
|
134
|
-
const name = x['name']
|
|
135
|
-
nameToId[name] = x['_id']
|
|
126
|
+
const { _id, name } = x; // x['name' as keyof typeof x]
|
|
127
|
+
nameToId[name] = _id; // x['_id' as keyof typeof x]
|
|
136
128
|
}
|
|
137
129
|
return nameToId;
|
|
138
130
|
}
|
|
@@ -173,7 +165,7 @@ export async function convertAssemblyNameToId(address, accessToken, namesOrIds,
|
|
|
173
165
|
ids.push(x);
|
|
174
166
|
}
|
|
175
167
|
else if (verbose) {
|
|
176
|
-
|
|
168
|
+
stderr.write(`Warning: Omitting unknown assembly: "${x}"\n`);
|
|
177
169
|
}
|
|
178
170
|
}
|
|
179
171
|
if (removeDuplicates) {
|
|
@@ -221,15 +213,6 @@ export function filterJsonList(json, keep, key) {
|
|
|
221
213
|
}
|
|
222
214
|
return results;
|
|
223
215
|
}
|
|
224
|
-
export const getUserCredentials = () => {
|
|
225
|
-
try {
|
|
226
|
-
const content = fs.readFileSync(CONFIG_PATH, { encoding: 'utf8' });
|
|
227
|
-
return JSON.parse(content);
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
216
|
export const generatePkceChallenge = () => {
|
|
234
217
|
const codeVerifier = crypto.randomBytes(64).toString('hex');
|
|
235
218
|
const codeChallenge = crypto
|
|
@@ -256,7 +239,7 @@ export const waitFor = (eventName, emitter) => {
|
|
|
256
239
|
return promise;
|
|
257
240
|
};
|
|
258
241
|
export async function submitAssembly(address, accessToken, body, force) {
|
|
259
|
-
|
|
242
|
+
let assemblies = await queryApollo(address, accessToken, 'assemblies');
|
|
260
243
|
for (const x of (await assemblies.json())) {
|
|
261
244
|
if (x['name'] === body.assemblyName) {
|
|
262
245
|
if (force) {
|
|
@@ -267,10 +250,6 @@ export async function submitAssembly(address, accessToken, body, force) {
|
|
|
267
250
|
}
|
|
268
251
|
}
|
|
269
252
|
}
|
|
270
|
-
const controller = new AbortController();
|
|
271
|
-
setTimeout(() => {
|
|
272
|
-
controller.abort();
|
|
273
|
-
}, 24 * 60 * 60 * 1000);
|
|
274
253
|
const auth = {
|
|
275
254
|
method: 'POST',
|
|
276
255
|
body: JSON.stringify(body),
|
|
@@ -278,60 +257,35 @@ export async function submitAssembly(address, accessToken, body, force) {
|
|
|
278
257
|
Authorization: `Bearer ${accessToken}`,
|
|
279
258
|
'Content-Type': 'application/json',
|
|
280
259
|
},
|
|
281
|
-
|
|
260
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
282
261
|
};
|
|
283
262
|
const url = new URL(localhostToAddress(`${address}/changes`));
|
|
284
263
|
const response = await fetch(url, auth);
|
|
285
264
|
if (!response.ok) {
|
|
286
265
|
const errorMessage = await createFetchErrorMessage(response, 'submitAssembly failed');
|
|
287
|
-
throw new
|
|
266
|
+
throw new Error(errorMessage);
|
|
288
267
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const fileBlob = await fileStream.blob();
|
|
295
|
-
const formData = new FormData();
|
|
296
|
-
formData.append('type', type);
|
|
297
|
-
formData.append('file', fileBlob);
|
|
298
|
-
const auth = {
|
|
299
|
-
method: 'POST',
|
|
300
|
-
body: formData,
|
|
301
|
-
headers: {
|
|
302
|
-
Authorization: `Bearer ${accessToken}`,
|
|
303
|
-
},
|
|
304
|
-
dispatcher: new Agent({
|
|
305
|
-
keepAliveTimeout: 10 * 60 * 1000,
|
|
306
|
-
keepAliveMaxTimeout: 10 * 60 * 1000, // 10 minutes
|
|
307
|
-
}),
|
|
308
|
-
};
|
|
309
|
-
const url = new URL(localhostToAddress(`${address}/files`));
|
|
310
|
-
const response = await fetch(url, auth);
|
|
311
|
-
if (!response.ok) {
|
|
312
|
-
const errorMessage = await createFetchErrorMessage(response, 'uploadFile failed');
|
|
313
|
-
throw new ConfigError(errorMessage);
|
|
268
|
+
assemblies = await queryApollo(address, accessToken, 'assemblies');
|
|
269
|
+
for (const x of (await assemblies.json())) {
|
|
270
|
+
if (x['name'] === body.assemblyName) {
|
|
271
|
+
return x;
|
|
272
|
+
}
|
|
314
273
|
}
|
|
315
|
-
|
|
316
|
-
return json['_id'];
|
|
274
|
+
throw new Error(`Failed to retrieve assembly ${body.assemblyName}`);
|
|
317
275
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
276
|
+
export async function readStdin() {
|
|
277
|
+
const chunks = [];
|
|
278
|
+
for await (const chunk of stdin) {
|
|
279
|
+
chunks.push(Buffer.from(chunk));
|
|
322
280
|
}
|
|
323
|
-
|
|
324
|
-
const re = new RegExp(`(?![^\\n]{1,${length}}$)([^\\n]{1,${length}})\\s`, 'g');
|
|
325
|
-
s = s.replaceAll(/ +/g, ' ');
|
|
326
|
-
const wr = s.replace(re, '$1\n');
|
|
327
|
-
return wr;
|
|
281
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
328
282
|
}
|
|
329
|
-
export function idReader(input, removeDuplicates = true) {
|
|
283
|
+
export async function idReader(input, removeDuplicates = true) {
|
|
330
284
|
let ids = [];
|
|
331
285
|
for (const xin of input) {
|
|
332
286
|
let data;
|
|
333
287
|
if (xin == '-') {
|
|
334
|
-
data =
|
|
288
|
+
data = await readStdin();
|
|
335
289
|
}
|
|
336
290
|
else if (fs.existsSync(xin)) {
|
|
337
291
|
data = fs.readFileSync(xin).toString();
|
|
@@ -340,14 +294,13 @@ export function idReader(input, removeDuplicates = true) {
|
|
|
340
294
|
data = xin;
|
|
341
295
|
}
|
|
342
296
|
try {
|
|
343
|
-
|
|
344
|
-
if (
|
|
345
|
-
|
|
297
|
+
let parsedData = JSON.parse(data);
|
|
298
|
+
if (!Array.isArray(parsedData)) {
|
|
299
|
+
parsedData = [parsedData];
|
|
346
300
|
}
|
|
347
|
-
for (const x of
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
ids.push(id);
|
|
301
|
+
for (const x of parsedData) {
|
|
302
|
+
if ('_id' in x && typeof x._id === 'string') {
|
|
303
|
+
ids.push(x._id);
|
|
351
304
|
}
|
|
352
305
|
}
|
|
353
306
|
}
|