diff --git a/packages/cli/README.md b/packages/cli/README.md index ecfe9dff..e3d136ed 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1 +1,215 @@ -# cli +# Bucket CLI + +Command-line interface for interacting with Bucket services. The CLI allows you to manage apps, features, authentication, and generate TypeScript types for your Bucket features. With this tool, you can streamline your feature flagging workflow directly from your terminal. + +## Quick Start + +Get started quickly by running the CLI directly: initializing the CLI, creating a feature, and generate the types all at once. + +```bash +# Initialize CLI (if not setup), create a feature, and generate types all at once +npx @bucketco/cli new +``` + +or install it locally + +```bash +# npm +npm install --save-dev @bucketco/cli + +# yarn +yarn add --dev @bucketco/cli +``` + +then + +```bash +# npm +npx bucket new + +# yarn +yarn bucket new +``` + +### Global installation + +You can also install the CLI globally adding the it to your PATH allowing you to use the shorthand `bucket` + +```bash +npm install -g @bucketco/cli + +bucket +``` + +### Individual commands + +Instead of running `new` you can call each step individually. + +```bash +# Initialize Bucket in your project (if not already setup) +bucket init + +# Create a new feature +bucket features create "My Feature" + +# Generate TypeScript types for your features +bucket features types +``` + +## Configuration + +The CLI creates a `bucket.config.json` file in your project directory when you run `bucket init`. This file contains all the necessary settings for your Bucket integration. + +### Configuration File Structure + +Here's a comprehensive list of configuration options available in the `bucket.config.json` file: + +```json +{ + "$schema": "https://unpkg.com/@bucketco/cli@latest/schema.json", + "baseUrl": "https://app.bucket.co", + "apiUrl": "https://app.bucket.co/api", + "appId": "ap123456789", + "typesOutput": "gen/features.ts", + "keyFormat": "camelCase" +} +``` + +| Option | Description | Default | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| `$schema` | Autocompletion for the config. `latest` can be replaced with a specific version. | "https://unpkg.com/@bucketco/cli@latest/schema.json" | +| `baseUrl` | Base URL for Bucket services. | "https://app.bucket.co" | +| `apiUrl` | API URL for Bucket services (overrides baseUrl for API calls). | "https://app.bucket.co/api" | +| `appId` | Your Bucket application ID. | Required | +| `typesOutput` | Path where TypeScript types will be generated. | "gen/features.ts" | +| `keyFormat` | Format for feature keys (options: custom, pascalCase, camelCase, snakeCaseUpper, snakeCaseLower, kebabCaseUpper, kebabCaseLower). | "custom" | + +You can override these settings using command-line options for individual commands. + +## Commands + +### `bucket init` + +Initialize a new Bucket configuration in your project. This creates a `bucket.config.json` file with your settings and prompts for any required information not provided via options. + +```bash +bucket init [--force] +``` + +Options: + +- `--force`: Overwrite existing configuration file if one exists +- `--app-id `: Set the application ID +- `--key-format `: Set the key format for features + +### `bucket new [featureName]` + +All-in-one command to get started quickly. This command combines `init`, feature creation, and type generation in a single step. Use this for the fastest way to get up and running with Bucket. + +```bash +bucket new "My Feature" [--key my-feature] [--app-id ap123456789] [--key-format custom] [--out gen/features.ts] +``` + +Options: + +- `--key`: Specific key for the feature +- `--app-id`: App ID to use +- `--key-format`: Format for feature keys (custom, snake, camel, etc.) +- `--out`: Path to generate TypeScript types + +If you prefer more control over each step, you can use the individual commands (`init`, `features create`, `features types`) instead. + +### `bucket login` + +Log in to your Bucket account. This will authenticate your CLI for subsequent operations and store credentials securely. + +```bash +bucket login +``` + +### `bucket logout` + +Log out from your Bucket account, removing stored credentials. + +```bash +bucket logout +``` + +### `bucket features` + +Manage your Bucket features with the following subcommands. + +#### `bucket features create [featureName]` + +Create a new feature in your Bucket app. The command guides you through the feature creation process with interactive prompts if options are not provided. + +```bash +bucket features create "My Feature" [--key my-feature] [--app-id ap123456789] [--key-format custom] +``` + +Options: + +- `--key`: Specific key for the feature +- `--app-id`: App ID to use +- `--key-format`: Format for feature keys + +#### `bucket features list` + +List all features for the current app. This helps you visualize what features are available and their current configurations. + +```bash +bucket features list [--app-id ap123456789] +``` + +Options: + +- `--app-id`: App ID to use + +#### `bucket features types` + +Generate TypeScript types for your features. This ensures type safety when using Bucket features in your TypeScript/JavaScript applications. + +```bash +bucket features types [--app-id ap123456789] [--out gen/features.ts] +``` + +Options: + +- `--app-id`: App ID to use +- `--out`: Path to generate TypeScript types + +### `bucket apps` + +Commands for managing Bucket apps. + +## Global Options + +These options can be used with any command: + +- `--debug`: Enable debug mode for verbose output +- `--base-url `: Set the base URL for Bucket API +- `--api-url `: Set the API URL directly (overrides base URL) +- `--help`: Display help information for a command + +## Development + +```bash +# Build the CLI +yarn build + +# Run the CLI locally +yarn bucket [command] + +# Lint and format code +yarn lint +yarn format +``` + +## Requirements + +- Node.js >=18.0.0 + +## License + +> MIT License +> Copyright (c) 2025 Bucket ApS diff --git a/packages/cli/commands/features.ts b/packages/cli/commands/features.ts index c36f54e1..825dd34a 100644 --- a/packages/cli/commands/features.ts +++ b/packages/cli/commands/features.ts @@ -80,7 +80,7 @@ export const listFeaturesAction = async () => { }; export const generateTypesAction = async () => { - const { baseUrl, appId, typesPath } = configStore.getConfig(); + const { baseUrl, appId, typesOutput } = configStore.getConfig(); let spinner: Ora | undefined; let featureKeys: string[] = []; @@ -103,9 +103,9 @@ export const generateTypesAction = async () => { spinner = ora("Generating feature types...").start(); const types = genDTS(featureKeys); const projectPath = configStore.getProjectPath(); - const outPath = isAbsolute(typesPath) - ? typesPath - : join(projectPath, typesPath); + const outPath = isAbsolute(typesOutput) + ? typesOutput + : join(projectPath, typesOutput); await mkdir(dirname(outPath), { recursive: true }); await writeFile(outPath, types); spinner.succeed( @@ -147,7 +147,7 @@ export function registerFeatureCommands(cli: Command) { // Update the config with the cli override values featuresCommand.hook("preAction", (_, command) => { const { appId, keyFormat, out } = command.opts(); - configStore.setConfig({ appId, keyFormat, typesPath: out }); + configStore.setConfig({ appId, keyFormat, typesOutput: out }); }); cli.addCommand(featuresCommand); diff --git a/packages/cli/commands/init.ts b/packages/cli/commands/init.ts index 7bba51e8..9d064973 100644 --- a/packages/cli/commands/init.ts +++ b/packages/cli/commands/init.ts @@ -6,7 +6,7 @@ import ora, { Ora } from "ora"; import { App, listApps } from "../services/bootstrap.js"; import { configStore } from "../stores/config.js"; -import { chalkBrand, DEFAULT_TYPES_PATH } from "../utils/constants.js"; +import { chalkBrand, DEFAULT_TYPES_OUTPUT } from "../utils/constants.js"; import { handleError } from "../utils/errors.js"; import { initOverrideOption } from "../utils/options.js"; @@ -69,16 +69,16 @@ export const initAction = async (args: InitArgs = {}) => { apps.find((app) => app.id === appId)?.featureKeyFormat ?? "custom"; // Get types output path - const typesPath = await input({ + const typesOutput = await input({ message: "Where should we generate the types?", - default: DEFAULT_TYPES_PATH, + default: DEFAULT_TYPES_OUTPUT, }); // Update config configStore.setConfig({ appId, keyFormat, - typesPath, + typesOutput, }); // Create config file diff --git a/packages/cli/commands/new.ts b/packages/cli/commands/new.ts index d3f0a13a..22abc7b9 100644 --- a/packages/cli/commands/new.ts +++ b/packages/cli/commands/new.ts @@ -46,6 +46,6 @@ export function registerNewCommand(cli: Command) { // Update the config with the cli override values cli.hook("preAction", (command) => { const { appId, keyFormat, out } = command.opts(); - configStore.setConfig({ appId, keyFormat, typesPath: out }); + configStore.setConfig({ appId, keyFormat, typesOutput: out }); }); } diff --git a/packages/cli/package.json b/packages/cli/package.json index c4e2b7b9..e90470d8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,10 +1,17 @@ { "name": "@bucketco/cli", - "version": "0.0.1", + "version": "0.1.0", "packageManager": "yarn@4.1.1", "description": "CLI for Bucket service", "main": "./dist/index.js", "type": "module", + "license": "MIT", + "author": "Bucket.", + "homepage": "https://docs.bucket.co/", + "repository": { + "type": "git", + "url": "https://github.com/bucketco/bucket-javascript-sdk.git" + }, "engines": { "node": ">=18.0.0" }, @@ -15,6 +22,9 @@ "dist", "schema.json" ], + "exports": { + ".": "./dist/index.js" + }, "scripts": { "build": "tsc", "bucket": "yarn build && node dist/index.js", diff --git a/packages/cli/schema.json b/packages/cli/schema.json index e8b54954..4d22ab5d 100644 --- a/packages/cli/schema.json +++ b/packages/cli/schema.json @@ -12,7 +12,7 @@ "appId": { "type": "string" }, - "typesPath": { + "typesOutput": { "type": "string" }, "keyFormat": { diff --git a/packages/cli/stores/config.ts b/packages/cli/stores/config.ts index 76cfa375..cd4a978b 100644 --- a/packages/cli/stores/config.ts +++ b/packages/cli/stores/config.ts @@ -8,7 +8,7 @@ import { CONFIG_FILE_NAME, DEFAULT_API_URL, DEFAULT_BASE_URL, - DEFAULT_TYPES_PATH, + DEFAULT_TYPES_OUTPUT, SCHEMA_URL, } from "../utils/constants.js"; import { ConfigValidationError, handleError } from "../utils/errors.js"; @@ -30,7 +30,7 @@ type Config = { baseUrl: string; apiUrl: string; appId: string | undefined; - typesPath: string; + typesOutput: string; keyFormat: KeyFormat; }; @@ -39,7 +39,7 @@ const defaultConfig: Config = { baseUrl: DEFAULT_BASE_URL, apiUrl: DEFAULT_API_URL, appId: undefined, - typesPath: DEFAULT_TYPES_PATH, + typesOutput: DEFAULT_TYPES_OUTPUT, keyFormat: "custom", }; diff --git a/packages/cli/utils/constants.ts b/packages/cli/utils/constants.ts index 7fe752f4..8d00b7bb 100644 --- a/packages/cli/utils/constants.ts +++ b/packages/cli/utils/constants.ts @@ -1,20 +1,16 @@ -import { createRequire } from "module"; import { join } from "path"; import chalk from "chalk"; -// https://github.com/nodejs/node/issues/51347#issuecomment-2111337854 -const packageJson = createRequire(import.meta.url)("../../package.json"); - export const CONFIG_FILE_NAME = "bucket.config.json"; export const AUTH_FILE = join( process.env.HOME ?? process.env.USERPROFILE ?? "", ".bucket-auth", ); -export const SCHEMA_URL = `https://unpkg.com/@bucketco/cli@${packageJson.version}/schema.json`; +export const SCHEMA_URL = `https://unpkg.com/@bucketco/cli@latest/schema.json`; export const DEFAULT_BASE_URL = "https://app.bucket.co"; export const DEFAULT_API_URL = `${DEFAULT_BASE_URL}/api`; -export const DEFAULT_TYPES_PATH = join("gen", "features.ts"); +export const DEFAULT_TYPES_OUTPUT = join("gen", "features.ts"); export const chalkBrand = chalk.hex("#847CFB"); diff --git a/packages/cli/utils/options.ts b/packages/cli/utils/options.ts index e07025b4..749e6553 100644 --- a/packages/cli/utils/options.ts +++ b/packages/cli/utils/options.ts @@ -28,7 +28,7 @@ export const initOverrideOption = new Option( export const typesOutOption = new Option( "-o, --out [path]", - `Output path for generated feature types. Falls back to typesPath value in ${CONFIG_FILE_NAME}.`, + `Output path for generated feature types. Falls back to typesOutput value in ${CONFIG_FILE_NAME}.`, ); export const keyFormatOption = new Option(