@apollo-annotation/cli 0.1.19 → 0.1.21
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 +297 -115
- package/dist/baseCommand.d.ts +1 -1
- package/dist/baseCommand.js +3 -4
- package/dist/commands/assembly/add-from-fasta.d.ts +22 -0
- package/dist/commands/assembly/add-from-fasta.js +157 -0
- package/dist/commands/assembly/{add-gff.d.ts → add-from-gff.d.ts} +5 -3
- package/dist/commands/assembly/add-from-gff.js +64 -0
- 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/sequence.js +4 -4
- package/dist/commands/change/get.js +7 -7
- package/dist/commands/config.js +4 -6
- package/dist/commands/feature/add-child.js +6 -5
- package/dist/commands/feature/check.js +6 -6
- package/dist/commands/feature/copy.js +5 -4
- package/dist/commands/feature/delete.js +4 -4
- package/dist/commands/feature/edit-attribute.js +6 -5
- package/dist/commands/feature/edit-coords.js +5 -5
- package/dist/commands/feature/edit-type.js +5 -5
- package/dist/commands/feature/edit.js +5 -5
- package/dist/commands/feature/get-id.js +5 -5
- package/dist/commands/feature/get.js +3 -3
- package/dist/commands/feature/import.d.ts +5 -3
- package/dist/commands/feature/import.js +15 -14
- package/dist/commands/feature/search.js +6 -6
- 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 +18 -0
- package/dist/commands/file/upload.js +89 -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 +11 -15
- package/dist/commands/logout.js +2 -2
- package/dist/commands/refseq/add-alias.d.ts +3 -1
- package/dist/commands/refseq/add-alias.js +13 -12
- package/dist/commands/refseq/get.js +8 -8
- package/dist/commands/status.js +4 -3
- package/dist/commands/user/get.js +3 -3
- package/dist/fileCommand.d.ts +5 -0
- package/dist/fileCommand.js +76 -0
- package/dist/utils.d.ts +7 -21
- package/dist/utils.js +37 -109
- package/oclif.manifest.json +449 -90
- package/package.json +50 -43
- package/dist/commands/assembly/add-fasta.d.ts +0 -15
- package/dist/commands/assembly/add-fasta.js +0 -87
- package/dist/commands/assembly/add-gff.js +0 -63
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { Args } from '@oclif/core';
|
|
3
|
+
import { Agent, fetch } from 'undici';
|
|
4
|
+
import { ConfigError } from '../../ApolloConf.js';
|
|
5
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
6
|
+
import { localhostToAddress, createFetchErrorMessage } from '../../utils.js';
|
|
7
|
+
export default class SetConfig extends BaseCommand {
|
|
8
|
+
static summary = 'Set JBrowse configuration';
|
|
9
|
+
static description = 'Set JBrowse configuration in Apollo collaboration server';
|
|
10
|
+
static examples = [
|
|
11
|
+
{
|
|
12
|
+
description: 'Add JBrowse configuration:',
|
|
13
|
+
command: '<%= config.bin %> <%= command.id %> config.json',
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
static args = {
|
|
17
|
+
inputFile: Args.string({
|
|
18
|
+
description: 'JBrowse configuration file',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { args } = await this.parse(SetConfig);
|
|
24
|
+
if (!fs.existsSync(args.inputFile)) {
|
|
25
|
+
this.error(`File ${args.inputFile} does not exist`);
|
|
26
|
+
}
|
|
27
|
+
const access = await this.getAccess();
|
|
28
|
+
const filehandle = await fs.promises.open(args.inputFile);
|
|
29
|
+
const fileContent = await filehandle.readFile({ encoding: 'utf8' });
|
|
30
|
+
await filehandle.close();
|
|
31
|
+
const change = {
|
|
32
|
+
typeName: 'ImportJBrowseConfigChange',
|
|
33
|
+
newJBrowseConfig: JSON.parse(fileContent),
|
|
34
|
+
};
|
|
35
|
+
const auth = {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
body: JSON.stringify(change),
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `Bearer ${access.accessToken}`,
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
43
|
+
};
|
|
44
|
+
const url = new URL(localhostToAddress(`${access.address}/changes`));
|
|
45
|
+
const response = await fetch(url, auth);
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const errorMessage = await createFetchErrorMessage(response, 'Failed to add JBrowse configuration');
|
|
48
|
+
throw new ConfigError(errorMessage);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/commands/login.js
CHANGED
|
@@ -8,21 +8,21 @@ import * as querystring from 'node:querystring';
|
|
|
8
8
|
import { Errors, Flags, ux } from '@oclif/core';
|
|
9
9
|
import open from 'open';
|
|
10
10
|
import { fetch } from 'undici';
|
|
11
|
-
import { ApolloConf } from '../ApolloConf.js';
|
|
11
|
+
import { ApolloConf, KEYS } from '../ApolloConf.js';
|
|
12
12
|
import { BaseCommand } from '../baseCommand.js';
|
|
13
|
-
import { basicCheckConfig, createFetchErrorMessage,
|
|
13
|
+
import { basicCheckConfig, createFetchErrorMessage, localhostToAddress, waitFor, } from '../utils.js';
|
|
14
14
|
export default class Login extends BaseCommand {
|
|
15
15
|
static summary = 'Login to Apollo';
|
|
16
|
-
static description =
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
static description = 'Use the provided credentials to obtain and save the token to access Apollo. \
|
|
17
|
+
Once the token for the given profile has been saved in the configuration file, users do not normally \
|
|
18
|
+
need to execute this command again unless the token has expired. To setup a new profile use "apollo config"';
|
|
19
19
|
static examples = [
|
|
20
20
|
{
|
|
21
|
-
description:
|
|
21
|
+
description: 'The most basic and probably most typical usage is to login using the default profile in configuration file:',
|
|
22
22
|
command: '<%= config.bin %> <%= command.id %>',
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
description:
|
|
25
|
+
description: 'Login with a different profile:',
|
|
26
26
|
command: '<%= config.bin %> <%= command.id %> --profile my-profile',
|
|
27
27
|
},
|
|
28
28
|
];
|
|
@@ -71,7 +71,7 @@ export default class Login extends BaseCommand {
|
|
|
71
71
|
let userCredentials = { accessToken: '' };
|
|
72
72
|
try {
|
|
73
73
|
if (!flags.force) {
|
|
74
|
-
await this.checkUserAlreadyLoggedIn();
|
|
74
|
+
await this.checkUserAlreadyLoggedIn(config, profileName);
|
|
75
75
|
}
|
|
76
76
|
if (accessType === 'root' || flags.username !== undefined) {
|
|
77
77
|
const username = flags.username ??
|
|
@@ -104,13 +104,9 @@ export default class Login extends BaseCommand {
|
|
|
104
104
|
}
|
|
105
105
|
config.set(`${profileName}.accessToken`, userCredentials.accessToken);
|
|
106
106
|
}
|
|
107
|
-
async checkUserAlreadyLoggedIn() {
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
const alreadyLoggedIn = Object.keys(userCredentials).every((key) => Boolean(userCredentials[key]));
|
|
113
|
-
if (!alreadyLoggedIn) {
|
|
107
|
+
async checkUserAlreadyLoggedIn(userCredentials, profileName) {
|
|
108
|
+
const accessToken = userCredentials.get(`${profileName}.${KEYS.accessToken}`);
|
|
109
|
+
if (!accessToken) {
|
|
114
110
|
return;
|
|
115
111
|
}
|
|
116
112
|
const reAuthenticate = await ux.confirm("You're already logged. Do you want to re-authenticate? (y/n)");
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { ApolloConf, KEYS } from '../ApolloConf.js';
|
|
3
3
|
import { BaseCommand } from '../baseCommand.js';
|
|
4
|
-
import { basicCheckConfig
|
|
4
|
+
import { basicCheckConfig } from '../utils.js';
|
|
5
5
|
export default class Logout extends BaseCommand {
|
|
6
6
|
static summary = 'Logout of Apollo';
|
|
7
|
-
static description =
|
|
7
|
+
static description = 'Logout by removing the access token from the selected profile';
|
|
8
8
|
static examples = [
|
|
9
9
|
{
|
|
10
10
|
description: 'Logout default profile:',
|
|
@@ -6,8 +6,10 @@ export default class AddRefNameAlias extends BaseCommand<typeof AddRefNameAlias>
|
|
|
6
6
|
description: string;
|
|
7
7
|
command: string;
|
|
8
8
|
}[];
|
|
9
|
+
static args: {
|
|
10
|
+
'input-file': import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
9
12
|
static flags: {
|
|
10
|
-
'input-file': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
13
|
assembly: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
14
|
};
|
|
13
15
|
run(): Promise<void>;
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import { Agent, fetch } from 'undici';
|
|
3
|
-
import { Flags } from '@oclif/core';
|
|
3
|
+
import { Args, Flags } from '@oclif/core';
|
|
4
4
|
import { BaseCommand } from '../../baseCommand.js';
|
|
5
|
-
import { createFetchErrorMessage, localhostToAddress, queryApollo,
|
|
5
|
+
import { createFetchErrorMessage, localhostToAddress, queryApollo, } from '../../utils.js';
|
|
6
6
|
import { ConfigError } from '../../ApolloConf.js';
|
|
7
7
|
export default class AddRefNameAlias extends BaseCommand {
|
|
8
8
|
static summary = 'Add reference name aliases from a file';
|
|
9
|
-
static description =
|
|
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
10
|
static examples = [
|
|
11
11
|
{
|
|
12
12
|
description: 'Add reference name aliases:',
|
|
13
|
-
command: '<%= config.bin %> <%= command.id %>
|
|
13
|
+
command: '<%= config.bin %> <%= command.id %> alias.txt -a myAssembly',
|
|
14
14
|
},
|
|
15
15
|
];
|
|
16
|
-
static
|
|
17
|
-
'input-file':
|
|
18
|
-
char: 'i',
|
|
16
|
+
static args = {
|
|
17
|
+
'input-file': Args.string({
|
|
19
18
|
description: 'Input refname alias file',
|
|
20
19
|
required: true,
|
|
21
20
|
}),
|
|
21
|
+
};
|
|
22
|
+
static flags = {
|
|
22
23
|
assembly: Flags.string({
|
|
23
24
|
char: 'a',
|
|
24
25
|
description: 'Name for this assembly.',
|
|
@@ -26,12 +27,12 @@ export default class AddRefNameAlias extends BaseCommand {
|
|
|
26
27
|
}),
|
|
27
28
|
};
|
|
28
29
|
async run() {
|
|
29
|
-
const { flags } = await this.parse(AddRefNameAlias);
|
|
30
|
-
if (!fs.existsSync(
|
|
31
|
-
this.error(`File ${
|
|
30
|
+
const { args, flags } = await this.parse(AddRefNameAlias);
|
|
31
|
+
if (!fs.existsSync(args['input-file'])) {
|
|
32
|
+
this.error(`File ${args['input-file']} does not exist`);
|
|
32
33
|
}
|
|
33
|
-
const access = await this.getAccess(
|
|
34
|
-
const filehandle = await fs.promises.open(
|
|
34
|
+
const access = await this.getAccess();
|
|
35
|
+
const filehandle = await fs.promises.open(args['input-file']);
|
|
35
36
|
const fileContent = await filehandle.readFile({ encoding: 'utf8' });
|
|
36
37
|
await filehandle.close();
|
|
37
38
|
const lines = fileContent.split('\n');
|
|
@@ -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;
|
|
@@ -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 = [];
|
|
@@ -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/utils.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
|
+
import type { SerializedAddAssemblyAndFeaturesFromFileChange, SerializedAddAssemblyFromExternalChange, SerializedAddAssemblyFromFileChange } from '@apollo-annotation/shared';
|
|
2
3
|
import { Response } from 'undici';
|
|
3
4
|
import { ApolloConf } from './ApolloConf.js';
|
|
5
|
+
import { ApolloAssemblySnapshot } from '@apollo-annotation/mst';
|
|
4
6
|
export declare const CLI_SERVER_ADDRESS = "http://127.0.0.1:5657";
|
|
5
7
|
export declare const CLI_SERVER_ADDRESS_CALLBACK = "http://127.0.0.1:5657/auth/callback";
|
|
6
8
|
export declare class CheckError extends Error {
|
|
@@ -17,38 +19,22 @@ export declare function basicCheckConfig(configFile: string, profileName: string
|
|
|
17
19
|
*/
|
|
18
20
|
export declare function localhostToAddress(url: string): string;
|
|
19
21
|
export declare function deleteAssembly(address: string, accessToken: string, assemblyId: string): Promise<void>;
|
|
20
|
-
export declare function getAssembly(address: string, accessToken: string, assemblyNameOrId: string): Promise<
|
|
22
|
+
export declare function getAssembly(address: string, accessToken: string, assemblyNameOrId: string): Promise<ApolloAssemblySnapshot>;
|
|
21
23
|
export declare function getRefseqId(address: string, accessToken: string, refseqNameOrId?: string, inAssemblyNameOrId?: string): Promise<string[]>;
|
|
22
24
|
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>>;
|
|
25
|
+
export declare function assemblyNameToIdDict(address: string, accessToken: string): Promise<Record<string, string | undefined>>;
|
|
24
26
|
/** In input array namesOrIds, substitute common names with internal IDs */
|
|
25
27
|
export declare function convertAssemblyNameToId(address: string, accessToken: string, namesOrIds: string[], verbose?: boolean, removeDuplicates?: boolean): Promise<string[]>;
|
|
26
28
|
export declare function getFeatureById(address: string, accessToken: string, id: string): Promise<Response>;
|
|
27
29
|
export declare function getAssemblyFromRefseq(address: string, accessToken: string, refSeq: string): Promise<string>;
|
|
28
30
|
export declare function queryApollo(address: string, accessToken: string, endpoint: string): Promise<Response>;
|
|
29
31
|
export declare function filterJsonList(json: object[], keep: string[], key: string): object[];
|
|
30
|
-
export declare const getUserCredentials: () => UserCredentials | null;
|
|
31
32
|
export declare const generatePkceChallenge: () => {
|
|
32
33
|
state: string;
|
|
33
34
|
codeVerifier: string;
|
|
34
35
|
codeChallenge: string;
|
|
35
36
|
};
|
|
36
37
|
export declare const waitFor: <T>(eventName: string, emitter: EventEmitter) => Promise<T>;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
fileId: string;
|
|
41
|
-
}
|
|
42
|
-
interface bodyExternalFile {
|
|
43
|
-
assemblyName: string;
|
|
44
|
-
typeName: string;
|
|
45
|
-
externalLocation: {
|
|
46
|
-
fa: string;
|
|
47
|
-
fai: string;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
export declare function submitAssembly(address: string, accessToken: string, body: bodyLocalFile | bodyExternalFile, force: boolean): Promise<Response>;
|
|
51
|
-
export declare function uploadFile(address: string, accessToken: string, file: string, type: string): Promise<never>;
|
|
52
|
-
export declare function wrapLines(s: string, length?: number): string;
|
|
53
|
-
export declare function idReader(input: string[], removeDuplicates?: boolean): string[];
|
|
54
|
-
export {};
|
|
38
|
+
export declare function submitAssembly(address: string, accessToken: string, body: SerializedAddAssemblyFromFileChange | SerializedAddAssemblyFromExternalChange | SerializedAddAssemblyAndFeaturesFromFileChange, force: boolean): Promise<object>;
|
|
39
|
+
export declare function readStdin(): Promise<string>;
|
|
40
|
+
export declare function idReader(input: string[], removeDuplicates?: boolean): Promise<string[]>;
|
package/dist/utils.js
CHANGED
|
@@ -1,17 +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 * as path from 'node:path';
|
|
10
|
-
import { Transform, pipeline, } from 'node:stream';
|
|
11
|
-
import { SingleBar } from 'cli-progress';
|
|
3
|
+
import { stdin, stderr } from 'node:process';
|
|
12
4
|
import { Agent, fetch } from 'undici';
|
|
13
5
|
import { ApolloConf, ConfigError } from './ApolloConf.js';
|
|
14
|
-
const CONFIG_PATH = path.resolve(os.homedir(), '.clirc');
|
|
15
6
|
export const CLI_SERVER_ADDRESS = 'http://127.0.0.1:5657';
|
|
16
7
|
export const CLI_SERVER_ADDRESS_CALLBACK = `${CLI_SERVER_ADDRESS}/auth/callback`;
|
|
17
8
|
export class CheckError extends Error {
|
|
@@ -75,18 +66,16 @@ export async function deleteAssembly(address, accessToken, assemblyId) {
|
|
|
75
66
|
export async function getAssembly(address, accessToken, assemblyNameOrId) {
|
|
76
67
|
const assemblyId = await convertAssemblyNameToId(address, accessToken, [assemblyNameOrId]);
|
|
77
68
|
if (assemblyId.length === 0) {
|
|
78
|
-
|
|
69
|
+
throw new Error(`Assembly "${assemblyNameOrId}" not found`);
|
|
79
70
|
}
|
|
80
71
|
const res = await queryApollo(address, accessToken, 'assemblies');
|
|
81
72
|
const assemblies = (await res.json());
|
|
82
|
-
let assemblyObj = {};
|
|
83
73
|
for (const x of assemblies) {
|
|
84
74
|
if (x._id === assemblyId[0]) {
|
|
85
|
-
|
|
86
|
-
break;
|
|
75
|
+
return JSON.parse(JSON.stringify(x));
|
|
87
76
|
}
|
|
88
77
|
}
|
|
89
|
-
|
|
78
|
+
throw new Error(`Assembly "${assemblyNameOrId}" not found`);
|
|
90
79
|
}
|
|
91
80
|
export async function getRefseqId(address, accessToken, refseqNameOrId, inAssemblyNameOrId) {
|
|
92
81
|
if (refseqNameOrId === undefined && inAssemblyNameOrId === undefined) {
|
|
@@ -176,7 +165,7 @@ export async function convertAssemblyNameToId(address, accessToken, namesOrIds,
|
|
|
176
165
|
ids.push(x);
|
|
177
166
|
}
|
|
178
167
|
else if (verbose) {
|
|
179
|
-
|
|
168
|
+
stderr.write(`Warning: Omitting unknown assembly: "${x}"\n`);
|
|
180
169
|
}
|
|
181
170
|
}
|
|
182
171
|
if (removeDuplicates) {
|
|
@@ -224,15 +213,6 @@ export function filterJsonList(json, keep, key) {
|
|
|
224
213
|
}
|
|
225
214
|
return results;
|
|
226
215
|
}
|
|
227
|
-
export const getUserCredentials = () => {
|
|
228
|
-
try {
|
|
229
|
-
const content = fs.readFileSync(CONFIG_PATH, { encoding: 'utf8' });
|
|
230
|
-
return JSON.parse(content);
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
216
|
export const generatePkceChallenge = () => {
|
|
237
217
|
const codeVerifier = crypto.randomBytes(64).toString('hex');
|
|
238
218
|
const codeChallenge = crypto
|
|
@@ -259,14 +239,17 @@ export const waitFor = (eventName, emitter) => {
|
|
|
259
239
|
return promise;
|
|
260
240
|
};
|
|
261
241
|
export async function submitAssembly(address, accessToken, body, force) {
|
|
262
|
-
|
|
242
|
+
let assemblies = await queryApollo(address, accessToken, 'assemblies');
|
|
263
243
|
for (const x of (await assemblies.json())) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
244
|
+
const addedAssemblies = 'changes' in body ? body.changes : [body];
|
|
245
|
+
for (const addedAssembly of addedAssemblies) {
|
|
246
|
+
if (x.name === addedAssembly.assemblyName) {
|
|
247
|
+
if (force) {
|
|
248
|
+
await deleteAssembly(address, accessToken, x._id);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
throw new Error(`Error: Assembly "${addedAssembly.assemblyName}" already exists`);
|
|
252
|
+
}
|
|
270
253
|
}
|
|
271
254
|
}
|
|
272
255
|
}
|
|
@@ -283,86 +266,32 @@ export async function submitAssembly(address, accessToken, body, force) {
|
|
|
283
266
|
const response = await fetch(url, auth);
|
|
284
267
|
if (!response.ok) {
|
|
285
268
|
const errorMessage = await createFetchErrorMessage(response, 'submitAssembly failed');
|
|
286
|
-
throw new
|
|
287
|
-
}
|
|
288
|
-
return response;
|
|
289
|
-
}
|
|
290
|
-
class ProgressTransform extends Transform {
|
|
291
|
-
size = 0;
|
|
292
|
-
progressBar;
|
|
293
|
-
constructor(opts) {
|
|
294
|
-
super(opts);
|
|
295
|
-
this.progressBar = opts.progressBar;
|
|
296
|
-
}
|
|
297
|
-
_transform(chunk, _encoding, callback) {
|
|
298
|
-
this.size += chunk.length;
|
|
299
|
-
this.progressBar.update(this.size);
|
|
300
|
-
callback(null, chunk);
|
|
269
|
+
throw new Error(errorMessage);
|
|
301
270
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const body = pipeline(stream, progressTransform, (error) => {
|
|
310
|
-
if (error) {
|
|
311
|
-
progressBar.stop();
|
|
312
|
-
console.error('Error processing file.', error);
|
|
313
|
-
throw error;
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
const init = {
|
|
317
|
-
method: 'POST',
|
|
318
|
-
body,
|
|
319
|
-
duplex: 'half',
|
|
320
|
-
headers: {
|
|
321
|
-
Authorization: `Bearer ${accessToken}`,
|
|
322
|
-
'Content-Type': type,
|
|
323
|
-
'Content-Length': String(size),
|
|
324
|
-
},
|
|
325
|
-
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
326
|
-
};
|
|
327
|
-
const fileName = path.basename(file);
|
|
328
|
-
const url = new URL(localhostToAddress(`${address}/files`));
|
|
329
|
-
url.searchParams.set('name', fileName);
|
|
330
|
-
url.searchParams.set('type', type);
|
|
331
|
-
progressBar.start(size, 0);
|
|
332
|
-
try {
|
|
333
|
-
const response = await fetch(url, init);
|
|
334
|
-
if (!response.ok) {
|
|
335
|
-
const errorMessage = await createFetchErrorMessage(response, 'uploadFile failed');
|
|
336
|
-
throw new ConfigError(errorMessage);
|
|
271
|
+
assemblies = await queryApollo(address, accessToken, 'assemblies');
|
|
272
|
+
for (const x of (await assemblies.json())) {
|
|
273
|
+
const addedAssemblies = 'changes' in body ? body.changes : [body];
|
|
274
|
+
for (const addedAssembly of addedAssemblies) {
|
|
275
|
+
if (x.name === addedAssembly.assemblyName) {
|
|
276
|
+
return x;
|
|
277
|
+
}
|
|
337
278
|
}
|
|
338
|
-
const json = (await response.json());
|
|
339
|
-
return json['_id'];
|
|
340
|
-
}
|
|
341
|
-
catch (error) {
|
|
342
|
-
console.error(error);
|
|
343
|
-
throw error;
|
|
344
|
-
}
|
|
345
|
-
finally {
|
|
346
|
-
progressBar.stop();
|
|
347
279
|
}
|
|
280
|
+
throw new Error(`Failed to retrieve assembly from ${body.assembly}`);
|
|
348
281
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
282
|
+
export async function readStdin() {
|
|
283
|
+
const chunks = [];
|
|
284
|
+
for await (const chunk of stdin) {
|
|
285
|
+
chunks.push(Buffer.from(chunk));
|
|
353
286
|
}
|
|
354
|
-
|
|
355
|
-
const re = new RegExp(`(?![^\\n]{1,${length}}$)([^\\n]{1,${length}})\\s`, 'g');
|
|
356
|
-
s = s.replaceAll(/ +/g, ' ');
|
|
357
|
-
const wr = s.replace(re, '$1\n');
|
|
358
|
-
return wr;
|
|
287
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
359
288
|
}
|
|
360
|
-
export function idReader(input, removeDuplicates = true) {
|
|
289
|
+
export async function idReader(input, removeDuplicates = true) {
|
|
361
290
|
let ids = [];
|
|
362
291
|
for (const xin of input) {
|
|
363
292
|
let data;
|
|
364
293
|
if (xin == '-') {
|
|
365
|
-
data =
|
|
294
|
+
data = await readStdin();
|
|
366
295
|
}
|
|
367
296
|
else if (fs.existsSync(xin)) {
|
|
368
297
|
data = fs.readFileSync(xin).toString();
|
|
@@ -371,14 +300,13 @@ export function idReader(input, removeDuplicates = true) {
|
|
|
371
300
|
data = xin;
|
|
372
301
|
}
|
|
373
302
|
try {
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
|
|
303
|
+
let parsedData = JSON.parse(data);
|
|
304
|
+
if (!Array.isArray(parsedData)) {
|
|
305
|
+
parsedData = [parsedData];
|
|
377
306
|
}
|
|
378
|
-
for (const x of
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
ids.push(id);
|
|
307
|
+
for (const x of parsedData) {
|
|
308
|
+
if ('_id' in x && typeof x._id === 'string') {
|
|
309
|
+
ids.push(x._id);
|
|
382
310
|
}
|
|
383
311
|
}
|
|
384
312
|
}
|