Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@
"**/*.lock": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": ["bucketco", "openfeature"]
"cSpell.words": [
"booleanish",
"bucketco",
"openfeature",
"PKCE"
]
}
45 changes: 45 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ These options can be used with any command:
- `--debug`: Enable debug mode for verbose output.
- `--base-url <url>`: Set the base URL for Bucket API.
- `--api-url <url>`: Set the API URL directly (overrides base URL).
- `--api-key <key>`: Bucket API key for non-interactive authentication.
- `--help`: Display help information for a command.

## AI-Assisted Development
Expand Down Expand Up @@ -297,6 +298,50 @@ The command will guide you through:

_**Note: The setup uses [mcp-remote](https://github.com/geelen/mcp-remote) as a compatibility layer allowing the remote hosted Bucket MCP server to work with all editors/clients that support MCP STDIO servers. If your editor/client supports HTTP Streaming with OAuth you can connect to the Bucket MCP server directly.**_

## Using in CI/CD Pipelines (Beta)

The Bucket CLI is designed to work seamlessly in CI/CD pipelines. For automated environments where interactive login is not possible, use the `--api-key` option.

```bash
# Generate types in CI/CD
npx bucket apps list --api-key $BUCKET_API_KEY
```

**Important restrictions:**

- When using `--api-key`, the `login` and `logout` commands are disabled.
- API keys bypass all interactive authentication flows.
- Only _read-only_ access to Bucket API is granted at the moment.
- API keys are bound to one app only. Commands such as `apps list` will only return the bound app.
- Store API keys securely using your CI/CD platform's secret management.

### Primary Use Case: Type Validation in CI/CD

Use the `--check-only` flag with `features types` to validate that generated types are up-to-date:

```bash
# Check if types are current (exits with non-zero code if not)
npx bucket features types --check-only --api-key $BUCKET_API_KEY --app-id ap123456789
```

This is particularly useful for:

- **Pull Request validation**: Ensure developers have regenerated types after feature changes.
- **Build verification**: Confirm types are synchronized before deployment.
- **Automated quality checks**: Catch type drift in your CI pipeline.

Example CI workflow:

```yaml
# GitHub Actions example
- name: Validate Bucket types
run: npx bucket features types --check-only --api-key ${{ secrets.BUCKET_API_KEY }}

- name: Generate types if validation fails
if: failure()
run: npx bucket features types --api-key ${{ secrets.BUCKET_API_KEY }}
```

## Development

```bash
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/commands/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import { handleError } from "../utils/errors.js";
export const listAppsAction = async () => {
const baseUrl = configStore.getConfig("baseUrl");
const spinner = ora(`Loading apps from ${chalk.cyan(baseUrl)}...`).start();

try {
const apps = await listApps();
const apps = listApps();
spinner.succeed(`Loaded apps from ${chalk.cyan(baseUrl)}.`);
console.table(apps.map(({ name, id, demo }) => ({ name, id, demo })));
} catch (error) {
spinner.fail("Failed to list apps.");
void handleError(error, "Apps List");
handleError(error, "Apps List");
}
};

Expand Down
40 changes: 36 additions & 4 deletions packages/cli/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,57 @@ import { handleError } from "../utils/errors.js";

export const loginAction = async () => {
const { baseUrl, apiUrl } = configStore.getConfig();
const { token, isApiKey } = authStore.getToken(baseUrl);

if (isApiKey) {
handleError(
"Login is not allowed when an API token was supplied.",
"Login",
);
}

if (token) {
console.log("Already logged in, nothing to do.");
return;
}

try {
await waitForAccessToken(baseUrl, apiUrl);
const { accessToken } = await waitForAccessToken(baseUrl, apiUrl);
await authStore.setToken(baseUrl, accessToken);

console.log(`Logged in to ${chalk.cyan(baseUrl)} successfully!`);
} catch (error) {
console.error("Login failed.");
void handleError(error, "Login");
handleError(error, "Login");
}
};

export const logoutAction = async () => {
const baseUrl = configStore.getConfig("baseUrl");

const { token, isApiKey } = authStore.getToken(baseUrl);

if (isApiKey) {
handleError(
"Logout is not allowed when an API token was supplied.",
"Logout",
);
}

if (!token) {
console.log("Not logged in, nothing to do.");
return;
}

const spinner = ora("Logging out...").start();

try {
await authStore.setToken(baseUrl, undefined);
await authStore.setToken(baseUrl, null);

spinner.succeed("Logged out successfully!");
} catch (error) {
spinner.fail("Logout failed.");
void handleError(error, "Logout");
handleError(error, "Logout");
}
};

Expand Down
83 changes: 0 additions & 83 deletions packages/cli/commands/companies.ts

This file was deleted.

Loading