@quantum-hub/qhubctl 1.1.5 → 1.3.0

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 (77) hide show
  1. package/README.md +136 -20
  2. package/dist/client/kqh/models/UpdateWorkflowServiceRequest.js +0 -11
  3. package/dist/commands/compress.d.ts +2 -0
  4. package/dist/commands/compress.js +23 -0
  5. package/dist/commands/datapool-upload.d.ts +2 -0
  6. package/dist/commands/datapool-upload.js +184 -0
  7. package/dist/commands/get-context.d.ts +2 -0
  8. package/dist/commands/get-context.js +12 -0
  9. package/dist/commands/init.d.ts +2 -0
  10. package/dist/commands/init.js +66 -0
  11. package/dist/commands/list-contexts.d.ts +2 -0
  12. package/dist/commands/list-contexts.js +28 -0
  13. package/dist/commands/login.d.ts +2 -0
  14. package/dist/commands/login.js +59 -0
  15. package/dist/commands/logout.d.ts +2 -0
  16. package/dist/commands/logout.js +20 -0
  17. package/dist/commands/openapi.d.ts +2 -0
  18. package/dist/commands/openapi.js +244 -0
  19. package/dist/commands/run.d.ts +2 -0
  20. package/dist/commands/run.js +126 -0
  21. package/dist/commands/serve.d.ts +2 -0
  22. package/dist/commands/serve.js +35 -0
  23. package/dist/commands/services.d.ts +2 -0
  24. package/dist/commands/services.js +48 -0
  25. package/dist/commands/set-context.d.ts +2 -0
  26. package/dist/commands/set-context.js +52 -0
  27. package/dist/commands/up.d.ts +2 -0
  28. package/dist/commands/up.js +161 -0
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.js +1 -1
  31. package/dist/lib/config-dir.d.ts +6 -0
  32. package/dist/lib/config-dir.js +8 -0
  33. package/dist/lib/entrypoint-resolver.js +2 -2
  34. package/dist/lib/output.d.ts +14 -0
  35. package/dist/lib/output.js +22 -0
  36. package/dist/main.d.ts +2 -0
  37. package/dist/main.js +8 -0
  38. package/dist/model/command.d.ts +14 -11
  39. package/dist/model/command.js +44 -40
  40. package/dist/program.d.ts +2 -0
  41. package/dist/program.js +47 -0
  42. package/dist/service/command-service.d.ts +1 -5
  43. package/dist/service/command-service.js +1 -5
  44. package/dist/service/quantum-hub-service.d.ts +1 -3
  45. package/dist/service/quantum-hub-service.js +2 -2
  46. package/package.json +30 -61
  47. package/bin/dev.cmd +0 -3
  48. package/bin/dev.js +0 -17
  49. package/bin/run.cmd +0 -3
  50. package/bin/run.js +0 -12
  51. package/dist/commands/compress/index.d.ts +0 -6
  52. package/dist/commands/compress/index.js +0 -25
  53. package/dist/commands/datapool/upload.d.ts +0 -23
  54. package/dist/commands/datapool/upload.js +0 -260
  55. package/dist/commands/get-context/index.d.ts +0 -6
  56. package/dist/commands/get-context/index.js +0 -10
  57. package/dist/commands/init/index.d.ts +0 -10
  58. package/dist/commands/init/index.js +0 -75
  59. package/dist/commands/list-contexts/index.d.ts +0 -9
  60. package/dist/commands/list-contexts/index.js +0 -30
  61. package/dist/commands/login/index.d.ts +0 -10
  62. package/dist/commands/login/index.js +0 -62
  63. package/dist/commands/logout/index.d.ts +0 -6
  64. package/dist/commands/logout/index.js +0 -18
  65. package/dist/commands/openapi/index.d.ts +0 -26
  66. package/dist/commands/openapi/index.js +0 -307
  67. package/dist/commands/run/index.d.ts +0 -18
  68. package/dist/commands/run/index.js +0 -150
  69. package/dist/commands/serve/index.d.ts +0 -13
  70. package/dist/commands/serve/index.js +0 -87
  71. package/dist/commands/services/index.d.ts +0 -14
  72. package/dist/commands/services/index.js +0 -65
  73. package/dist/commands/set-context/index.d.ts +0 -17
  74. package/dist/commands/set-context/index.js +0 -59
  75. package/dist/commands/up/index.d.ts +0 -19
  76. package/dist/commands/up/index.js +0 -190
  77. package/oclif.manifest.json +0 -530
@@ -1,25 +0,0 @@
1
- import { ux } from '@oclif/core';
2
- import fs from 'fs-extra';
3
- import path from 'node:path';
4
- import { zipProjectFolder } from '../../lib/up/zip.js';
5
- import { AbstractCommand } from '../../model/command.js';
6
- export default class Compress extends AbstractCommand {
7
- static description = `Compresses the current project and creates a ZIP file. Use the '.dockerignore' file to exclude files and directories from the ZIP file.`;
8
- static examples = [
9
- '$ qhubctl compress',
10
- ];
11
- async run() {
12
- ux.action.start('Compressing project');
13
- const targetDirectory = process.cwd();
14
- const targetFilename = 'service.zip';
15
- const targetFilePath = path.join(targetDirectory, '/', targetFilename);
16
- // remove the file if it already exists
17
- if (fs.existsSync(targetFilePath)) {
18
- fs.unlinkSync(targetFilePath);
19
- }
20
- await zipProjectFolder('./', targetDirectory, targetFilename);
21
- ux.action.stop('Succeeded.');
22
- ux.stdout(`\nFile created at: ${targetFilePath}`);
23
- this.exit();
24
- }
25
- }
@@ -1,23 +0,0 @@
1
- import { AuthenticatedCommand } from '../../model/command.js';
2
- import { HubPlatformClient } from "@quantum-hub/qhub-api/platform";
3
- export default class DatapoolUpload extends AuthenticatedCommand {
4
- static readonly description = "Upload files to a data pool";
5
- static readonly examples: string[];
6
- static readonly flags: {
7
- file: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
8
- 'datapool-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
- };
10
- hubPlatformClient: HubPlatformClient;
11
- init(): Promise<void>;
12
- run(): Promise<void>;
13
- private ensureFilesExist;
14
- private ensureDatapoolExists;
15
- private createOrSelectDataPool;
16
- private promptForDatapoolAction;
17
- private selectExistingDatapool;
18
- private createDatapool;
19
- private uploadToDatapool;
20
- private handleError;
21
- private extractError;
22
- private printHttpSpecificError;
23
- }
@@ -1,260 +0,0 @@
1
- import { input, select } from '@inquirer/prompts';
2
- import { Flags, ux } from '@oclif/core';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { AuthenticatedCommand } from '../../model/command.js';
6
- import { HubPlatformClient, HubPlatformError } from "@quantum-hub/qhub-api/platform";
7
- export default class DatapoolUpload extends AuthenticatedCommand {
8
- static description = 'Upload files to a data pool';
9
- static examples = [
10
- '$ qhubctl datapool upload --file ./data/dataset.csv',
11
- '$ qhubctl datapool upload --file ./data/dataset.csv --file ./data/metadata.json',
12
- '$ qhubctl datapool upload -f ./data/dataset.csv -f ./data/metadata.json --datapool-id 550e8400-e29b-41d4-a716-446655440000',
13
- ];
14
- static flags = {
15
- file: Flags.string({
16
- char: 'f',
17
- description: 'Path to a file to upload (can be specified multiple times)',
18
- required: true,
19
- multiple: true,
20
- }),
21
- 'datapool-id': Flags.string({
22
- char: 'd',
23
- description: 'ID of the data pool to upload the files to (optional - will prompt to create a new one if not provided)',
24
- required: false,
25
- }),
26
- };
27
- hubPlatformClient;
28
- async init() {
29
- await this.parse(DatapoolUpload);
30
- await super.init();
31
- // Initialize the new Quantum Hub API client with proper configuration
32
- // The new SDK expects the full base path including /qc-catalog
33
- const baseUrl = this.userConfig.endpoint?.basePath
34
- ? `${this.userConfig.endpoint.basePath}/qc-catalog`
35
- : undefined; // Will use the default environment if no custom endpoint is set
36
- const apiKey = this.userConfig.auth?.value;
37
- this.hubPlatformClient = new HubPlatformClient({
38
- baseUrl: baseUrl,
39
- apiKey: apiKey,
40
- organizationId: this.userConfig.context?.isOrganization ? this.userConfig.context.id : undefined,
41
- });
42
- }
43
- async run() {
44
- const { flags } = await this.parse(DatapoolUpload);
45
- const filePaths = flags.file;
46
- let datapoolId = flags['datapool-id'];
47
- this.ensureFilesExist(filePaths);
48
- // Handle datapool ID - check if exists or prompt to create
49
- datapoolId = await this.ensureDatapoolExists(datapoolId, filePaths);
50
- for (const filePath of filePaths) {
51
- const fileName = path.basename(filePath);
52
- ux.action.start(`Uploading ${fileName} to data pool ${datapoolId}`);
53
- await this.uploadToDatapool(datapoolId, filePath);
54
- }
55
- }
56
- ensureFilesExist(filePaths) {
57
- // Validate files exist
58
- for (const filePath of filePaths) {
59
- if (!fs.existsSync(filePath)) {
60
- this.error(`File not found: ${filePath}`);
61
- }
62
- // Check if file is readable
63
- try {
64
- fs.accessSync(filePath, fs.constants.R_OK);
65
- }
66
- catch {
67
- this.error(`Cannot read file: ${filePath}`);
68
- }
69
- }
70
- }
71
- async ensureDatapoolExists(datapoolId, filePaths) {
72
- // If no datapool ID provided, prompt to create or select one
73
- if (!datapoolId) {
74
- this.log('No data pool ID provided. You can create a new data pool or select an existing one.');
75
- return await this.createOrSelectDataPool(filePaths);
76
- }
77
- // If datapool ID provided, check if it exists
78
- try {
79
- await this.hubPlatformClient.dataPools.getDataPool({ "id": datapoolId });
80
- return datapoolId;
81
- }
82
- catch (error) {
83
- if (error instanceof HubPlatformError && error.statusCode === 404) {
84
- this.log(`Data pool ${datapoolId} not found. Would you like to create a new data pool instead?`);
85
- return await this.createOrSelectDataPool(filePaths);
86
- }
87
- this.handleError(error, datapoolId);
88
- throw error;
89
- }
90
- }
91
- async createOrSelectDataPool(filePaths) {
92
- const action = await this.promptForDatapoolAction();
93
- if (action === 'create') {
94
- const newDatapoolId = await this.createDatapool(filePaths[0]);
95
- if (!newDatapoolId) {
96
- this.error('Failed to create datapool');
97
- }
98
- return newDatapoolId;
99
- }
100
- else {
101
- // List and select existing datapool
102
- return await this.selectExistingDatapool();
103
- }
104
- }
105
- async promptForDatapoolAction() {
106
- // First, check if there are any existing DataPools
107
- try {
108
- const dataPools = await this.hubPlatformClient.dataPools.getDataPools();
109
- if (dataPools.length === 0) {
110
- this.log('No data pools found. Creating a new one...');
111
- return 'create';
112
- }
113
- // Offer choice between creating new or selecting existing using select prompt
114
- return await select({
115
- message: 'What would you like to do?',
116
- choices: [
117
- { name: 'Create a new data pool', value: 'create' },
118
- { name: 'Select an existing data pool', value: 'select' }
119
- ],
120
- default: 'create'
121
- });
122
- }
123
- catch {
124
- // If we can't list datapools, default to creating
125
- return 'create';
126
- }
127
- }
128
- async selectExistingDatapool() {
129
- try {
130
- const dataPools = await this.hubPlatformClient.dataPools.getDataPools();
131
- if (dataPools.length === 0) {
132
- this.log('No existing data pools found. Creating a new one...');
133
- const newDatapoolId = await this.createDatapool('upload');
134
- if (!newDatapoolId) {
135
- this.error('Failed to create datapool');
136
- }
137
- return newDatapoolId;
138
- }
139
- this.log('\nAvailable data pools:');
140
- dataPools.forEach((pool, index) => {
141
- this.log(`${index + 1}. ${pool.name} (${pool.id})`);
142
- });
143
- const selection = await input({
144
- message: `Select a data pool (1-${dataPools.length}) or enter the ID directly:`,
145
- });
146
- // Check if it's a number (index selection)
147
- const index = parseInt(selection, 10);
148
- if (!isNaN(index) && index >= 1 && index <= dataPools.length) {
149
- return dataPools[index - 1].id;
150
- }
151
- // Assume it's a direct ID
152
- return selection;
153
- }
154
- catch {
155
- this.error('Failed to retrieve data pools');
156
- }
157
- }
158
- async createDatapool(suggestedName) {
159
- try {
160
- const name = await input({
161
- message: 'Enter a name for the new data pool:',
162
- default: `Data Pool for ${suggestedName}`,
163
- });
164
- const datapool = await this.hubPlatformClient.dataPools.createDataPool({
165
- name,
166
- });
167
- this.log(`✓ Created new data pool: ${datapool.name} (${datapool.id})`);
168
- return datapool.id;
169
- }
170
- catch (error) {
171
- if (error instanceof HubPlatformError) {
172
- const errorMessage = error.body || error.message || 'Unknown API error occurred';
173
- this.error(`Failed to create data pool (HTTP ${error.statusCode}): ${JSON.stringify(errorMessage)}`);
174
- }
175
- else {
176
- const errorMessage = error instanceof Error ? error.message : String(error);
177
- this.error(`Failed to create data pool: ${errorMessage}`);
178
- }
179
- }
180
- }
181
- async uploadToDatapool(datapoolId, filePath) {
182
- const fileName = path.basename(filePath);
183
- try {
184
- const fileStream = fs.createReadStream(filePath);
185
- const result = await this.hubPlatformClient.dataPools.addDataPoolFile({ "id": datapoolId, file: fileStream });
186
- ux.action.stop('✓');
187
- this.log(`Successfully uploaded ${fileName} to data pool ${datapoolId}`);
188
- this.log(`File ID: ${result.id}`);
189
- }
190
- catch (error) {
191
- this.handleError(error, datapoolId);
192
- }
193
- }
194
- handleError(error, datapoolId) {
195
- ux.action.stop('✗');
196
- if (error instanceof HubPlatformError) {
197
- const statusCode = error.statusCode ?? 500; // Default to 500 if statusCode is not set
198
- let errorMessage = 'Unknown API error occurred';
199
- if (error.body) {
200
- if (typeof error.body === 'string') {
201
- errorMessage = error.body;
202
- }
203
- else if (typeof error.body === 'object') {
204
- errorMessage = this.extractError(error);
205
- }
206
- else if (error.message) {
207
- errorMessage = error.message;
208
- }
209
- }
210
- else if (error.message) {
211
- errorMessage = error.message;
212
- }
213
- this.printHttpSpecificError(datapoolId || 'unknown', statusCode, errorMessage);
214
- return error;
215
- }
216
- else {
217
- const errorMessage = error instanceof Error ? error.message : String(error);
218
- this.error(`Unexpected Error: ${errorMessage}`);
219
- }
220
- }
221
- extractError(error) {
222
- const bodyObj = error.body;
223
- if (bodyObj.errorMessage) {
224
- return bodyObj.errorMessage;
225
- }
226
- else if (bodyObj.detail) {
227
- return bodyObj.detail;
228
- }
229
- else if (bodyObj.message) {
230
- return bodyObj.message;
231
- }
232
- else {
233
- return JSON.stringify(error.body);
234
- }
235
- }
236
- printHttpSpecificError(datapoolId, statusCode, errorMessage) {
237
- // Provide specific error messages based on status code
238
- if (statusCode === 404) {
239
- throw new Error(`Data pool not found: ${datapoolId}`);
240
- }
241
- else if (statusCode === 403) {
242
- throw new Error(`Access denied. You don't have permission to upload to data pool: ${datapoolId}`);
243
- }
244
- else if (statusCode === 400) {
245
- throw new Error(`Bad request. Please check the data pool ID and file format. Details: ${errorMessage}`);
246
- }
247
- else if (statusCode === 401) {
248
- throw new Error(`Authentication failed. Please login again using 'qhubctl login'`);
249
- }
250
- else if (statusCode === 413) {
251
- throw new Error(`File too large. The file exceeds the maximum allowed size for data pool uploads`);
252
- }
253
- else if (statusCode === 415) {
254
- throw new Error(`Unsupported file type. Please check if the file format is supported`);
255
- }
256
- else {
257
- throw new Error(`Failed to upload file (HTTP ${statusCode}): ${errorMessage}`);
258
- }
259
- }
260
- }
@@ -1,6 +0,0 @@
1
- import { AuthenticatedCommand } from '../../model/command.js';
2
- export default class GetContext extends AuthenticatedCommand {
3
- static description: string;
4
- static examples: string[];
5
- run(): Promise<void>;
6
- }
@@ -1,10 +0,0 @@
1
- import { AuthenticatedCommand } from '../../model/command.js';
2
- export default class GetContext extends AuthenticatedCommand {
3
- static description = 'Get the current context, i.e., the personal or organization account you are currently working with.';
4
- static examples = [
5
- '$ qhubctl get-context',
6
- ];
7
- async run() {
8
- // printing the current context is done by parent 'init' method
9
- }
10
- }
@@ -1,10 +0,0 @@
1
- import { AbstractCommand } from '../../model/command.js';
2
- export default class Init extends AbstractCommand {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
- 'non-interactive': import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
- };
9
- run(): Promise<void>;
10
- }
@@ -1,75 +0,0 @@
1
- import { Flags, ux } from '@oclif/core';
2
- import fs from 'fs-extra';
3
- import path from 'node:path';
4
- import { DEFAULT_STARTER, promptUserInput } from '../../lib/init-user-input.js';
5
- import { randomName } from '../../lib/random-name.js';
6
- import { downloadRepository, extractStarter } from '../../lib/repository.js';
7
- import { AbstractCommand } from '../../model/command.js';
8
- import { Runtime } from '../../model/managed-service-config.js';
9
- import { writeServiceConfig } from '../../service/service-config-service.js';
10
- export default class Init extends AbstractCommand {
11
- static description = 'Bootstrap project to create a service.';
12
- static examples = [
13
- '$ qhubctl init',
14
- ];
15
- static flags = {
16
- name: Flags.string({ description: 'The name of the service', required: false }),
17
- 'non-interactive': Flags.boolean({
18
- description: 'Run it in non-interactive mode',
19
- required: false,
20
- }),
21
- };
22
- async run() {
23
- const { flags } = await this.parse(Init);
24
- const nonInteractive = flags['non-interactive'];
25
- let name = flags.name ?? randomName();
26
- const input = nonInteractive ? {
27
- cpu: 1,
28
- descriptionFile: 'README.md',
29
- gpu: undefined,
30
- memory: 1,
31
- name: name,
32
- starter: DEFAULT_STARTER,
33
- } : await promptUserInput(name);
34
- name = input.name || name;
35
- // use current directory if no template is selected
36
- const targetDirectory = input.starter ? path.join(process.cwd(), name) : path.join(process.cwd());
37
- // exit if the target directory already exists (only if a starter is selected)
38
- if (input.starter && fs.existsSync(targetDirectory)) {
39
- ux.error(`Destination ${targetDirectory} already exists. Please choose another name.`);
40
- }
41
- const serviceConfig = {
42
- name,
43
- descriptionFile: input.descriptionFile ?? 'README.md',
44
- resources: {
45
- cpu: input.cpu,
46
- memory: input.memory,
47
- },
48
- runtime: input.starter ? input.starter.runtime : Runtime.PYTHON_TEMPLATE,
49
- };
50
- if (input.gpu) {
51
- serviceConfig.resources.gpu = {
52
- count: 1,
53
- type: input.gpu,
54
- };
55
- }
56
- // make sure the target directory exists if a starter is selected
57
- if (input.starter) {
58
- fs.mkdirSync(targetDirectory);
59
- }
60
- writeServiceConfig(targetDirectory, serviceConfig);
61
- if (input.starter) {
62
- const zip = await downloadRepository(input.starter.url);
63
- const starterName = path.basename(input.starter.url, '.zip');
64
- extractStarter(zip, starterName, targetDirectory);
65
- }
66
- ux.stdout('\u{1F389} Initialized project. Happy hacking!');
67
- if (input.starter) {
68
- ux.stdout('\n Next steps:');
69
- ux.stdout(` \u{2022} cd ${name}`);
70
- ux.stdout(' \u{2022} qhubctl up (deploys your code as a service to Kipu Quantum Hub)');
71
- ux.stdout(' \u{2022} qhubclt run (executes your service using the data from the input directory)');
72
- }
73
- ux.stdout('');
74
- }
75
- }
@@ -1,9 +0,0 @@
1
- import { AuthenticatedCommand } from '../../model/command.js';
2
- import QuantumHubService from '../../service/quantum-hub-service.js';
3
- export default class ListContexts extends AuthenticatedCommand {
4
- static description: string;
5
- static examples: string[];
6
- quantumHubService: QuantumHubService;
7
- init(): Promise<void>;
8
- run(): Promise<void>;
9
- }
@@ -1,30 +0,0 @@
1
- import { ux } from '@oclif/core';
2
- import Table from 'tty-table';
3
- import { AuthenticatedCommand } from '../../model/command.js';
4
- import QuantumHubService from '../../service/quantum-hub-service.js';
5
- export default class ListContexts extends AuthenticatedCommand {
6
- static description = 'Retrieves the available contexts, i.e., the personal or organizational accounts available to you to work with.';
7
- static examples = [
8
- '$ qhubctl list-contexts',
9
- ];
10
- quantumHubService;
11
- async init() {
12
- await super.init();
13
- this.quantumHubService = new QuantumHubService(this, this.config, this.userConfig);
14
- }
15
- async run() {
16
- ux.action.start('Loading available contexts');
17
- const accounts = await this.quantumHubService.getAccounts();
18
- ux.action.stop('Done');
19
- const tableData = accounts
20
- .map(account => ({ displayName: account.displayName, id: account.id, isOrganization: account.isOrganization }));
21
- const header = [
22
- { value: "displayName", alias: "Name", align: "left" },
23
- { value: "id", alias: "ID", align: "left" },
24
- { value: "isOrganization", alias: "Account", width: 14, formatter: (value) => value ? "Organization" : "Personal" },
25
- ];
26
- const t = Table(header, tableData);
27
- ux.stdout(t.render());
28
- ux.stdout();
29
- }
30
- }
@@ -1,10 +0,0 @@
1
- import { AbstractCommand } from '../../model/command.js';
2
- export default class Login extends AbstractCommand {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
- 'base-path': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
- };
9
- run(): Promise<void>;
10
- }
@@ -1,62 +0,0 @@
1
- import { password } from '@inquirer/prompts';
2
- import { Flags, ux } from '@oclif/core';
3
- import { AbstractCommand } from '../../model/command.js';
4
- import { AuthType, defaultBasePath } from '../../model/user-config.js';
5
- import AuthService from '../../service/auth-service.js';
6
- import { writeUserConfig } from '../../service/user-config-service.js';
7
- export default class Login extends AbstractCommand {
8
- static description = 'Login with your credentials';
9
- static examples = [
10
- '$ qhubctl login -t <personal access token>',
11
- `$ qhubctl login -t <personal access token> --base-path ${defaultBasePath}`,
12
- ];
13
- static flags = {
14
- token: Flags.string({ char: 't', description: 'Your personal access token', required: false }),
15
- 'base-path': Flags.string({ description: 'Custom base path for authentication (development)', required: false }),
16
- };
17
- async run() {
18
- const { flags } = await this.parse(Login);
19
- let { token } = flags;
20
- const { 'base-path': basePath } = flags;
21
- if (!token) {
22
- token = await password({ message: 'Enter or paste your personal access token?', mask: true });
23
- }
24
- if (!token) {
25
- throw new Error('Invalid credentials. Please try again.');
26
- }
27
- // Show warning if custom base path is provided
28
- if (basePath) {
29
- this.showCustomBasePathWarning();
30
- }
31
- ux.action.start('Login');
32
- // Create temporary config with custom basePath for authentication
33
- const tempUserConfig = basePath ? {
34
- ...this.userConfig,
35
- endpoint: {
36
- basePath,
37
- defaultHeaders: this.userConfig.endpoint?.defaultHeaders || {}
38
- }
39
- } : this.userConfig;
40
- const user = await new AuthService(tempUserConfig).authenticate(token);
41
- const userConfig = {
42
- ...this.userConfig,
43
- auth: {
44
- type: AuthType.API_KEY,
45
- value: token,
46
- },
47
- context: {
48
- id: user.id,
49
- displayName: `${user.firstname} ${user.lastname}`,
50
- isOrganization: false,
51
- },
52
- ...(basePath && {
53
- endpoint: {
54
- basePath,
55
- defaultHeaders: this.userConfig.endpoint?.defaultHeaders || {}
56
- }
57
- })
58
- };
59
- writeUserConfig(this.config.configDir, userConfig);
60
- ux.action.stop('successful');
61
- }
62
- }
@@ -1,6 +0,0 @@
1
- import { AbstractCommand } from '../../model/command.js';
2
- export default class Logout extends AbstractCommand {
3
- static description: string;
4
- static examples: string[];
5
- run(): Promise<void>;
6
- }
@@ -1,18 +0,0 @@
1
- import { ux } from '@oclif/core';
2
- import { AbstractCommand } from '../../model/command.js';
3
- import { writeUserConfig } from '../../service/user-config-service.js';
4
- export default class Logout extends AbstractCommand {
5
- static description = 'Logout';
6
- static examples = [
7
- '$ qhubctl logout',
8
- ];
9
- async run() {
10
- ux.action.start('Logout');
11
- writeUserConfig(this.config.configDir, {
12
- ...this.userConfig,
13
- auth: undefined,
14
- context: undefined,
15
- });
16
- ux.action.stop('successful');
17
- }
18
- }
@@ -1,26 +0,0 @@
1
- import { AbstractCommand } from '../../model/command.js';
2
- export default class Openapi extends AbstractCommand {
3
- static readonly description: string;
4
- static readonly examples: string[];
5
- static readonly flags: {
6
- force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
- file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
- format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
- entrypoint: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
- package: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
- method: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
- };
13
- run(): Promise<void>;
14
- private getErrorMessage;
15
- private isErrorWithMessage;
16
- private checkDeprecatedFiles;
17
- private determineOutputPath;
18
- private generateFromCode;
19
- private validateCommandResult;
20
- private formatPythonError;
21
- private fetchDefaultTemplate;
22
- private displaySuccess;
23
- private isProjectSupported;
24
- private showRuntimeNotSupportedWarning;
25
- private showConfigurationHelp;
26
- }