Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cubejs-cli): Completely move CLI to TypeScript (#1281)
* feat(cubejs-cli): Move token command to TS * feat(cubejs-cli): Extract auth command to own module * feat(cubejs-cli): Migra cli.js to TS * feat(cubejs-cli): Move the last part to TS * fix(cubejs-cli): expiry/secret are optional * feat(linter): Improve configuration for TS * misc(cubejs-cli): Fix lint errors
- Loading branch information
Showing
10 changed files
with
269 additions
and
186 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import program from 'commander'; | ||
|
||
import { configureDevServerCommand } from './command/dev-server'; | ||
import { configureServerCommand } from './command/server'; | ||
import { configureDeployCommand } from './command/deploy'; | ||
import { configureCreateCommand } from './command/create'; | ||
import { configureGenerateCommand } from './command/generate'; | ||
import { configureTokenCommand } from './command/token'; | ||
import { configureAuthCommand } from './command/auth'; | ||
import { loadCliManifest } from './utils'; | ||
|
||
const packageJson = loadCliManifest(); | ||
|
||
program.name(Object.keys(packageJson.bin)[0]) | ||
.version(packageJson.version); | ||
|
||
program | ||
.usage('<command> [options]') | ||
.on('--help', () => { | ||
console.log(''); | ||
console.log('Use cubejs <command> --help for more information about a command.'); | ||
console.log(''); | ||
}); | ||
|
||
(async () => { | ||
await configureAuthCommand(program); | ||
await configureTokenCommand(program); | ||
await configureCreateCommand(program); | ||
await configureGenerateCommand(program); | ||
await configureDeployCommand(program); | ||
await configureDevServerCommand(program); | ||
await configureServerCommand(program); | ||
|
||
if (!process.argv.slice(2).length) { | ||
program.help(); | ||
} | ||
|
||
program.parse(process.argv); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import type { CommanderStatic } from 'commander'; | ||
import { displayError, event } from '../utils'; | ||
import { Config } from '../config'; | ||
|
||
const authenticate = async (currentToken: string) => { | ||
const config = new Config(); | ||
await config.addAuthToken(currentToken); | ||
|
||
await event('Cube Cloud CLI Authenticate'); | ||
console.log('Token successfully added!'); | ||
}; | ||
|
||
export function configureAuthCommand(program: CommanderStatic): void { | ||
program | ||
.command('auth <token>') | ||
.description('Authenticate access to Cube Cloud') | ||
.action( | ||
(currentToken) => authenticate(currentToken) | ||
.catch(e => displayError(e.stack || e)) | ||
) | ||
.on('--help', () => { | ||
console.log(''); | ||
console.log('Examples:'); | ||
console.log(''); | ||
console.log(' $ cubejs auth eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXBsb3ltZW50SWQiOiIxIiwidXJsIjoiaHR0cHM6Ly9leGFtcGxlcy5jdWJlY2xvdWQuZGV2IiwiaWF0IjoxNTE2MjM5MDIyfQ.La3MiuqfGigfzADl1wpxZ7jlb6dY60caezgqIOoHt-c'); | ||
console.log(' $ cubejs deploy'); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import chalk from 'chalk'; | ||
import jwt from 'jsonwebtoken'; | ||
import type { CommanderStatic } from 'commander'; | ||
import { displayError, event, requireFromPackage } from '../utils'; | ||
|
||
export const defaultExpiry = '30 days'; | ||
|
||
const parsePayload = (payloadArray: string[] = []) => { | ||
const result = {}; | ||
|
||
payloadArray.forEach((entry = '') => { | ||
const [key, value] = entry.split('='); | ||
if (key && value) result[key] = value; | ||
}); | ||
|
||
return result; | ||
}; | ||
|
||
type TokenOptions = { | ||
expiry?: string; | ||
secret?: string; | ||
expiresIn?: string | ||
payload: string[] | ||
userContext: string[] | ||
}; | ||
|
||
export const token = async (options: TokenOptions) => { | ||
event('Generate Token'); | ||
|
||
const CubejsServer = await requireFromPackage('@cubejs-backend/server'); | ||
const { expiry = defaultExpiry, secret = CubejsServer.apiSecret() } = options; | ||
|
||
if (!secret) { | ||
throw new Error('No app secret found'); | ||
} | ||
|
||
const extraOptions: Record<string, string> = {}; | ||
|
||
if (expiry !== '0') { | ||
extraOptions.expiresIn = expiry; | ||
} | ||
|
||
const payload = { | ||
...parsePayload(options.payload), | ||
u: parsePayload(options.userContext), | ||
}; | ||
|
||
console.log('Generating Cube.js JWT token'); | ||
console.log(''); | ||
console.log(`${chalk.yellow('-----------------------------------------------------------------------------------------')}`); | ||
console.log(` ${chalk.yellow('Use these manually generated tokens in production with caution.')}`); | ||
console.log(` ${chalk.yellow(`Please refer to ${chalk.cyan('https://cube.dev/docs/security')} for production security best practices.`)}`); | ||
console.log(`${chalk.yellow('-----------------------------------------------------------------------------------------')}`); | ||
console.log(''); | ||
console.log(`Expires in: ${chalk.green(expiry)}`); | ||
console.log(`Payload: ${chalk.green(JSON.stringify(payload))}`); | ||
console.log(''); | ||
|
||
const signedToken = jwt.sign(payload, secret, extraOptions); | ||
console.log(`Token: ${chalk.green(signedToken)}`); | ||
await event('Generate Token Success'); | ||
return signedToken; | ||
}; | ||
|
||
export const collect = (val, memo) => [val, ...memo]; | ||
|
||
export function configureTokenCommand(program: CommanderStatic) { | ||
program | ||
.command('token') | ||
.option('-e, --expiry [expiry]', 'Token expiry. Set to 0 for no expiry') | ||
.option('-s, --secret [secret]', 'Cube.js app secret. Also can be set via environment variable CUBEJS_API_SECRET') | ||
.option('-p, --payload [values]', 'Payload. Example: -p foo=bar', collect, []) | ||
.option('-u, --user-context [values]', 'USER_CONTEXT. Example: -u baz=qux', collect, []) | ||
.description('Create JWT token') | ||
.action( | ||
(options) => token(options) | ||
.catch(e => displayError(e.stack || e)) | ||
) | ||
.on('--help', () => { | ||
console.log(''); | ||
console.log('Examples:'); | ||
console.log(''); | ||
console.log(' $ cubejs token -e "1 day" -p foo=bar -p cool=true'); | ||
}); | ||
} |
Oops, something went wrong.