@apollo-annotation/cli 0.1.10

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.
Files changed (81) hide show
  1. package/README.md +899 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +9 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +8 -0
  6. package/dist/Config.d.ts +43 -0
  7. package/dist/Config.js +233 -0
  8. package/dist/baseCommand.d.ts +21 -0
  9. package/dist/baseCommand.js +62 -0
  10. package/dist/commands/assembly/add-fasta.d.ts +15 -0
  11. package/dist/commands/assembly/add-fasta.js +98 -0
  12. package/dist/commands/assembly/add-gff.d.ts +16 -0
  13. package/dist/commands/assembly/add-gff.js +76 -0
  14. package/dist/commands/assembly/check.d.ts +15 -0
  15. package/dist/commands/assembly/check.js +148 -0
  16. package/dist/commands/assembly/delete.d.ts +14 -0
  17. package/dist/commands/assembly/delete.js +43 -0
  18. package/dist/commands/assembly/get.d.ts +9 -0
  19. package/dist/commands/assembly/get.js +33 -0
  20. package/dist/commands/assembly/get.test.d.ts +1 -0
  21. package/dist/commands/assembly/get.test.js +50 -0
  22. package/dist/commands/assembly/sequence.d.ts +16 -0
  23. package/dist/commands/assembly/sequence.js +117 -0
  24. package/dist/commands/change/get.d.ts +9 -0
  25. package/dist/commands/change/get.js +35 -0
  26. package/dist/commands/change/get.test.d.ts +1 -0
  27. package/dist/commands/change/get.test.js +22 -0
  28. package/dist/commands/config.d.ts +25 -0
  29. package/dist/commands/config.js +217 -0
  30. package/dist/commands/config.test.d.ts +1 -0
  31. package/dist/commands/config.test.js +188 -0
  32. package/dist/commands/feature/add-child.d.ts +17 -0
  33. package/dist/commands/feature/add-child.js +120 -0
  34. package/dist/commands/feature/check.d.ts +14 -0
  35. package/dist/commands/feature/check.js +97 -0
  36. package/dist/commands/feature/copy.d.ts +17 -0
  37. package/dist/commands/feature/copy.js +110 -0
  38. package/dist/commands/feature/delete.d.ts +11 -0
  39. package/dist/commands/feature/delete.js +99 -0
  40. package/dist/commands/feature/edit-attribute.d.ts +16 -0
  41. package/dist/commands/feature/edit-attribute.js +100 -0
  42. package/dist/commands/feature/edit-coords.d.ts +15 -0
  43. package/dist/commands/feature/edit-coords.js +109 -0
  44. package/dist/commands/feature/edit-type.d.ts +10 -0
  45. package/dist/commands/feature/edit-type.js +70 -0
  46. package/dist/commands/feature/edit.d.ts +13 -0
  47. package/dist/commands/feature/edit.js +81 -0
  48. package/dist/commands/feature/get-id.d.ts +14 -0
  49. package/dist/commands/feature/get-id.js +56 -0
  50. package/dist/commands/feature/get.d.ts +16 -0
  51. package/dist/commands/feature/get.js +87 -0
  52. package/dist/commands/feature/import.d.ts +15 -0
  53. package/dist/commands/feature/import.js +83 -0
  54. package/dist/commands/feature/search.d.ts +14 -0
  55. package/dist/commands/feature/search.js +91 -0
  56. package/dist/commands/login.d.ts +21 -0
  57. package/dist/commands/login.js +206 -0
  58. package/dist/commands/login.test.d.ts +1 -0
  59. package/dist/commands/login.test.js +52 -0
  60. package/dist/commands/logout.d.ts +10 -0
  61. package/dist/commands/logout.js +41 -0
  62. package/dist/commands/logout.test.d.ts +1 -0
  63. package/dist/commands/logout.test.js +67 -0
  64. package/dist/commands/refseq/get.d.ts +13 -0
  65. package/dist/commands/refseq/get.js +44 -0
  66. package/dist/commands/status.d.ts +6 -0
  67. package/dist/commands/status.js +38 -0
  68. package/dist/commands/status.test.d.ts +1 -0
  69. package/dist/commands/status.test.js +54 -0
  70. package/dist/commands/user/get.d.ts +14 -0
  71. package/dist/commands/user/get.js +46 -0
  72. package/dist/commands/user/get.test.d.ts +1 -0
  73. package/dist/commands/user/get.test.js +23 -0
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.js +1 -0
  76. package/dist/test/fixtures.d.ts +7 -0
  77. package/dist/test/fixtures.js +40 -0
  78. package/dist/utils.d.ts +54 -0
  79. package/dist/utils.js +373 -0
  80. package/oclif.manifest.json +1632 -0
  81. package/package.json +100 -0
package/dist/utils.js ADDED
@@ -0,0 +1,373 @@
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
+ import * as crypto from 'node:crypto';
7
+ import * as fs from 'node:fs';
8
+ import * as os from 'node:os';
9
+ import * as path from 'node:path';
10
+ import { Agent, FormData, Response, fetch } from 'undici';
11
+ import { Config, ConfigError } from './Config.js';
12
+ const CONFIG_PATH = path.resolve(os.homedir(), '.clirc');
13
+ export const CLI_SERVER_ADDRESS = 'http://127.0.0.1:5657';
14
+ export const CLI_SERVER_ADDRESS_CALLBACK = `${CLI_SERVER_ADDRESS}/auth/callback`;
15
+ export class CheckError extends Error {
16
+ }
17
+ export async function createFetchErrorMessage(response, additionalText) {
18
+ let errorMessage;
19
+ try {
20
+ errorMessage = await response.text();
21
+ }
22
+ catch {
23
+ errorMessage = '';
24
+ }
25
+ const responseMessage = `${response.status} ${response.statusText}${errorMessage ? ` (${errorMessage})` : ''}`;
26
+ return `${additionalText ? `${additionalText} — ` : ''}${responseMessage}`;
27
+ }
28
+ export function checkConfigfileExists(configFile) {
29
+ if (!fs.existsSync(configFile)) {
30
+ throw new ConfigError(`Configuration file "${configFile}" does not exist. Please run "apollo config" first`);
31
+ }
32
+ }
33
+ export function checkProfileExists(profileName, config) {
34
+ if (!config.getProfileNames().includes(profileName)) {
35
+ throw new ConfigError(`Profile "${profileName}" does not exist. Please run "apollo config" to set this profile up or choose a different profile`);
36
+ }
37
+ }
38
+ export function basicCheckConfig(configFile, profileName) {
39
+ checkConfigfileExists(configFile);
40
+ const config = new Config(configFile);
41
+ checkProfileExists(profileName, config);
42
+ }
43
+ /**
44
+ * @deprecated Use this function while we wait to resolve the TypeError when using localhost in fetch.
45
+ */
46
+ export function localhostToAddress(url) {
47
+ /** This is hacked function that should become redundant: On my MacOS (?)
48
+ * localhost must be converted to address otherwise fetch throws TypeError
49
+ * */
50
+ return url.replace('//localhost', '127.0.0.1');
51
+ }
52
+ export async function deleteAssembly(address, accessToken, assemblyId) {
53
+ const body = {
54
+ typeName: 'DeleteAssemblyChange',
55
+ assembly: assemblyId,
56
+ };
57
+ const auth = {
58
+ method: 'POST',
59
+ body: JSON.stringify(body),
60
+ headers: {
61
+ Authorization: `Bearer ${accessToken}`,
62
+ 'Content-Type': 'application/json',
63
+ },
64
+ };
65
+ const url = new URL(localhostToAddress(`${address}/changes`));
66
+ const response = await fetch(url, auth);
67
+ if (!response.ok) {
68
+ const errorMessage = await createFetchErrorMessage(response, 'deleteAssembly failed');
69
+ throw new Error(errorMessage);
70
+ }
71
+ }
72
+ export async function getAssembly(address, accessToken, assemblyNameOrId) {
73
+ const assemblyId = await convertAssemblyNameToId(address, accessToken, [assemblyNameOrId]);
74
+ if (assemblyId.length === 0) {
75
+ return {};
76
+ }
77
+ const res = await queryApollo(address, accessToken, 'assemblies');
78
+ const assemblies = (await res.json());
79
+ let assemblyObj = {};
80
+ for (const x of assemblies) {
81
+ if (x['_id'] === assemblyId[0]) {
82
+ assemblyObj = JSON.parse(JSON.stringify(x));
83
+ break;
84
+ }
85
+ }
86
+ return assemblyObj;
87
+ }
88
+ export async function getRefseqId(address, accessToken, refseqNameOrId, inAssemblyNameOrId) {
89
+ if (refseqNameOrId === undefined && inAssemblyNameOrId === undefined) {
90
+ throw new Error('Please provide refseq and/or assembly');
91
+ }
92
+ if (inAssemblyNameOrId === undefined) {
93
+ inAssemblyNameOrId = '';
94
+ }
95
+ let assemblyId = [];
96
+ if (inAssemblyNameOrId !== '') {
97
+ assemblyId = await convertAssemblyNameToId(address, accessToken, [
98
+ inAssemblyNameOrId,
99
+ ]);
100
+ if (assemblyId.length !== 1) {
101
+ throw new Error(`Assembly name or assembly id returned ${assemblyId.length} assemblies instead of just one`);
102
+ }
103
+ }
104
+ const res = await queryApollo(address, accessToken, 'refSeqs');
105
+ const refSeqs = (await res.json());
106
+ const refseqIds = [];
107
+ const nAssemblies = new Set();
108
+ for (const x of refSeqs) {
109
+ const aid = x['assembly'];
110
+ const rid = x['_id'];
111
+ const rname = x['name'];
112
+ if (refseqNameOrId === rid ||
113
+ refseqNameOrId === rname ||
114
+ refseqNameOrId === undefined) {
115
+ if (inAssemblyNameOrId === '' || assemblyId.includes(aid)) {
116
+ refseqIds.push(rid);
117
+ nAssemblies.add(aid);
118
+ }
119
+ else {
120
+ //
121
+ }
122
+ }
123
+ if (nAssemblies.size > 1) {
124
+ throw new Error(`Sequence name "${refseqNameOrId}" found in more than one assembly`);
125
+ }
126
+ }
127
+ return refseqIds;
128
+ }
129
+ async function checkNameToIdDict(address, accessToken) {
130
+ const asm = await queryApollo(address, accessToken, 'checks/types');
131
+ const ja = (await asm.json());
132
+ const nameToId = {};
133
+ for (const x of ja) {
134
+ const name = x['name'];
135
+ nameToId[name] = x['_id'];
136
+ }
137
+ return nameToId;
138
+ }
139
+ export async function convertCheckNameToId(address, accessToken, namesOrIds) {
140
+ const nameToId = await checkNameToIdDict(address, accessToken);
141
+ const ids = [];
142
+ for (const x of namesOrIds) {
143
+ if (nameToId[x] !== undefined) {
144
+ ids.push(nameToId[x]);
145
+ }
146
+ else if (Object.values(nameToId).includes(x)) {
147
+ ids.push(x);
148
+ }
149
+ else {
150
+ throw new CheckError(`Check name or id "${x}" not found`);
151
+ }
152
+ }
153
+ return ids;
154
+ }
155
+ export async function assemblyNameToIdDict(address, accessToken) {
156
+ const asm = await queryApollo(address, accessToken, 'assemblies');
157
+ const ja = (await asm.json());
158
+ const nameToId = {};
159
+ for (const x of ja) {
160
+ nameToId[x['name']] = x['_id'];
161
+ }
162
+ return nameToId;
163
+ }
164
+ /** In input array namesOrIds, substitute common names with internal IDs */
165
+ export async function convertAssemblyNameToId(address, accessToken, namesOrIds, verbose = true, removeDuplicates = true) {
166
+ const nameToId = await assemblyNameToIdDict(address, accessToken);
167
+ let ids = [];
168
+ for (const x of namesOrIds) {
169
+ if (nameToId[x] !== undefined) {
170
+ ids.push(nameToId[x]);
171
+ }
172
+ else if (Object.values(nameToId).includes(x)) {
173
+ ids.push(x);
174
+ }
175
+ else if (verbose) {
176
+ process.stderr.write(`Warning: Omitting unknown assembly: "${x}"\n`);
177
+ }
178
+ }
179
+ if (removeDuplicates) {
180
+ ids = [...new Set(ids)];
181
+ }
182
+ return ids;
183
+ }
184
+ export async function getFeatureById(address, accessToken, id) {
185
+ const url = new URL(localhostToAddress(`${address}/features/${id}`));
186
+ const auth = {
187
+ headers: {
188
+ authorization: `Bearer ${accessToken}`,
189
+ },
190
+ };
191
+ const response = await fetch(url, auth);
192
+ return response;
193
+ }
194
+ export async function getAssemblyFromRefseq(address, accessToken, refSeq) {
195
+ const refSeqs = await queryApollo(address, accessToken, 'refSeqs');
196
+ const refJson = filterJsonList((await refSeqs.json()), [refSeq], '_id');
197
+ return refJson[0]['assembly'];
198
+ }
199
+ export async function queryApollo(address, accessToken, endpoint) {
200
+ const auth = {
201
+ headers: {
202
+ Authorization: `Bearer ${accessToken}`,
203
+ 'Content-Type': 'application/json',
204
+ },
205
+ };
206
+ const url = new URL(localhostToAddress(`${address}/${endpoint}`));
207
+ const response = await fetch(url, auth);
208
+ if (!response.ok) {
209
+ const errorMessage = await createFetchErrorMessage(response, 'queryApollo failed');
210
+ throw new ConfigError(errorMessage);
211
+ }
212
+ return response;
213
+ }
214
+ export function filterJsonList(json, keep, key) {
215
+ const unique = new Set(keep);
216
+ const results = [];
217
+ for (const x of json) {
218
+ if (Object.keys(x).includes(key) && unique.has(x[key])) {
219
+ results.push(x);
220
+ }
221
+ }
222
+ return results;
223
+ }
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
+ export const generatePkceChallenge = () => {
234
+ const codeVerifier = crypto.randomBytes(64).toString('hex');
235
+ const codeChallenge = crypto
236
+ .createHash('sha256')
237
+ .update(codeVerifier)
238
+ .digest('base64')
239
+ .replaceAll('+', '-')
240
+ .replaceAll('/', '_')
241
+ .replaceAll('=', '');
242
+ return {
243
+ state: crypto.randomBytes(32).toString('hex'),
244
+ codeVerifier,
245
+ codeChallenge,
246
+ };
247
+ };
248
+ export const waitFor = (eventName, emitter) => {
249
+ const promise = new Promise((resolve, reject) => {
250
+ const handleEvent = (eventData) => {
251
+ eventData instanceof Error ? reject(eventData) : resolve(eventData);
252
+ emitter.removeListener(eventName, handleEvent);
253
+ };
254
+ emitter.addListener(eventName, handleEvent);
255
+ });
256
+ return promise;
257
+ };
258
+ export async function submitAssembly(address, accessToken, body, force) {
259
+ const assemblies = await queryApollo(address, accessToken, 'assemblies');
260
+ for (const x of (await assemblies.json())) {
261
+ if (x['name'] === body.assemblyName) {
262
+ if (force) {
263
+ await deleteAssembly(address, accessToken, x['_id']);
264
+ }
265
+ else {
266
+ throw new Error(`Error: Assembly "${body.assemblyName}" already exists`);
267
+ }
268
+ }
269
+ }
270
+ const controller = new AbortController();
271
+ setTimeout(() => {
272
+ controller.abort();
273
+ }, 24 * 60 * 60 * 1000);
274
+ const auth = {
275
+ method: 'POST',
276
+ body: JSON.stringify(body),
277
+ headers: {
278
+ Authorization: `Bearer ${accessToken}`,
279
+ 'Content-Type': 'application/json',
280
+ },
281
+ signal: controller.signal,
282
+ };
283
+ const url = new URL(localhostToAddress(`${address}/changes`));
284
+ const response = await fetch(url, auth);
285
+ if (!response.ok) {
286
+ const errorMessage = await createFetchErrorMessage(response, 'submitAssembly failed');
287
+ throw new ConfigError(errorMessage);
288
+ }
289
+ return response;
290
+ }
291
+ export async function uploadFile(address, accessToken, file, type) {
292
+ const stream = fs.createReadStream(file, 'utf8');
293
+ const fileStream = new Response(stream);
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
+ try {
311
+ const response = await fetch(url, auth);
312
+ if (!response.ok) {
313
+ const errorMessage = await createFetchErrorMessage(response, 'uploadFile failed');
314
+ throw new ConfigError(errorMessage);
315
+ }
316
+ const json = (await response.json());
317
+ return json['_id'];
318
+ }
319
+ catch (error) {
320
+ console.error(error);
321
+ throw error;
322
+ }
323
+ }
324
+ /* Wrap text to max `length` per line */
325
+ export function wrapLines(s, length) {
326
+ if (length === undefined) {
327
+ length = 80;
328
+ }
329
+ // Credit: https://stackoverflow.com/questions/14484787/wrap-text-in-javascript
330
+ const re = new RegExp(`(?![^\\n]{1,${length}}$)([^\\n]{1,${length}})\\s`, 'g');
331
+ s = s.replaceAll(/ +/g, ' ');
332
+ const wr = s.replace(re, '$1\n');
333
+ return wr;
334
+ }
335
+ export function idReader(input, removeDuplicates = true) {
336
+ let ids = [];
337
+ for (const xin of input) {
338
+ let data;
339
+ if (xin == '-') {
340
+ data = fs.readFileSync('/dev/stdin').toString();
341
+ }
342
+ else if (fs.existsSync(xin)) {
343
+ data = fs.readFileSync(xin).toString();
344
+ }
345
+ else {
346
+ data = xin;
347
+ }
348
+ try {
349
+ data = JSON.parse(data);
350
+ if (data.length === undefined) {
351
+ data = [data];
352
+ }
353
+ for (const x of data) {
354
+ const id = x['_id'];
355
+ if (id !== undefined) {
356
+ ids.push(id);
357
+ }
358
+ }
359
+ }
360
+ catch {
361
+ for (let x of data.split('\n')) {
362
+ x = x.trim();
363
+ if (x !== '') {
364
+ ids.push(x);
365
+ }
366
+ }
367
+ }
368
+ }
369
+ if (removeDuplicates) {
370
+ ids = [...new Set(ids)];
371
+ }
372
+ return ids;
373
+ }