From c6942e3a4bfad14b1ce24951ac39e8f92aa2cac7 Mon Sep 17 00:00:00 2001 From: Devin Date: Mon, 3 Aug 2026 09:01:09 +0200 Subject: [PATCH] docs: restructure README with Divio and add CONTRIBUTING Make getting started easier with tutorials, how-tos, reference, and explanation sections, and document local development, version bumps, and releases for contributors. Co-authored-by: Cursor --- CONTRIBUTING.md | 347 +++++++++++++ README.md | 1233 ++++++++++------------------------------------- 2 files changed, 603 insertions(+), 977 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5bff8d9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,347 @@ +# Contributing to investec-ipb + +Thank you for contributing. This guide covers local development, tests, docs, version bumps, and releases. End-user docs live in [README.md](./README.md); packaging detail lives in [DISTRIBUTION.md](./DISTRIBUTION.md). + +## Table of contents + +- [Code of conduct](#code-of-conduct) +- [Prerequisites](#prerequisites) +- [Clone and install](#clone-and-install) +- [Project layout](#project-layout) +- [Run locally](#run-locally) +- [Build](#build) +- [Lint, format, and types](#lint-format-and-types) +- [Tests](#tests) +- [Adding or changing a command](#adding-or-changing-a-command) +- [Documentation](#documentation) +- [Demo GIFs (VHS tapes)](#demo-gifs-vhs-tapes) +- [Git hooks](#git-hooks) +- [Pull requests](#pull-requests) +- [Version bumps](#version-bumps) +- [Releasing](#releasing) +- [Useful environment variables for contributors](#useful-environment-variables-for-contributors) +- [Where to get help](#where-to-get-help) + +## Code of conduct + +Please follow [.github/CODE_OF_CONDUCT.md](./.github/CODE_OF_CONDUCT.md). Security reports: [.github/SECURITY.md](./.github/SECURITY.md). + +## Prerequisites + +- **Node.js ≥ 24** (see `engines` in `package.json`) +- **npm** (comes with Node) +- Optional for packaging: enough disk for `esbuild` + `@yao-pkg/pkg` binaries +- Optional for demo GIFs: [VHS](https://github.com/charmbracelet/vhs) and a terminal that can record + +Confirm: + +```sh +node -v # v24.x or newer +npm -v +``` + +## Clone and install + +```sh +git clone https://github.com/devinpearson/ipb.git +cd ipb +npm install +``` + +`npm install` runs `prepare` → Husky (git hooks). + +## Project layout + +| Path | Role | +|------|------| +| `src/index.ts` | CLI entry; version from `package.json` | +| `src/register-cli-commands.ts` | Commander registration | +| `src/cmds/` | Command implementations (kebab-case files) | +| `src/runtime-credentials.ts` | Credentials helpers (avoid importing `index` from cmds) | +| `src/utils/` | Shared modules; `src/utils.ts` re-exports | +| `src/errors.ts` | `CliError`, `ExitCode`, `ERROR_CODES` | +| `src/completion.ts` | Shell completion scripts | +| `bin/` | Build output (`tsc` + copied templates/assets) — gitignored | +| `templates/` | Project scaffolds for `ipb new` | +| `assets/` | README / VHS GIFs | +| `test/cmds/`, `test/utils/` | Vitest suites | +| `test/helpers/cli-mocks.ts` | Shared Vitest mocks | +| `skills/ipb/` | Portable agent skill for *using* the CLI | +| `GENERATED_README.md` | Auto-generated command reference | + +Stack: TypeScript (strict, ESM, NodeNext), Commander 14, Vitest, Biome. + +## Run locally + +Always build before running the compiled binary (or after changing TypeScript): + +```sh +npm run build +node bin/index.js --help +node bin/index.js cards --json +``` + +Shortcut while iterating: + +```sh +npm run build && node bin/index.js [options] +``` + +Link a global `ipb` that points at this checkout (optional): + +```sh +npm run build +npm link +ipb --version +``` + +Use a disposable profile so you do not overwrite personal credentials: + +```sh +ipb config --profile local-dev --client-id … --client-secret … --api-key … +ipb cards --profile local-dev +``` + +Mock APIs without hitting Investec (where supported): + +```sh +DEBUG=true node bin/index.js accounts +# or +IPB_MOCK_APIS=1 node bin/index.js accounts +``` + +Skip npm update checks while developing offline / recording tapes: + +```sh +IPB_NO_UPDATE_CHECK=1 node bin/index.js --help +``` + +## Build + +```sh +npm run build # clean → tsc → copy templates/assets/instructions +npm run type-check # tsc only (no emit side effects beyond typecheck script) +npm run clean # remove bin/ +``` + +Standalone binary path (for packaging smoke tests): + +```sh +npm run bundle # esbuild → dist-bundle/index.cjs (injects version) +npm run pkg:linux # example platform target — see package.json scripts +npm run verify:ci # build + test:run + bundle (also used by pre-push) +``` + +## Lint, format, and types + +```sh +npm run lint # Biome check +npm run lint:fix # Biome auto-fix +npm run format # Biome format write +npm run format:check +npm run lint:md # markdownlint-cli2 +npm run lint:md:fix +npm run type-check +``` + +Full gate used before publish / CI-style checks: + +```sh +npm run ci +# build + type-check + lint + lint:md + format:check + test:run + npm audit +``` + +Style notes (Biome): single quotes, semicolons, 2-space indent, line width 100. ESM imports use `.js` extensions. + +## Tests + +```sh +npm test # Vitest watch +npm run test:run # single run (CI / pre-push path) +npm run dev # alias of vitest watch +``` + +Focused runs: + +```sh +npm run test:run -- test/cmds/deploy.test.ts +npm run test:run -- test/utils/cli-errors.test.ts +``` + +### Conventions + +- One primary file per command area under `test/cmds/`. +- Mock `runtime-credentials` with the async factory + `getRuntimeCredentialsMock` from `test/helpers/cli-mocks.ts`. +- Prefer `vi.importActual` on `utils` and override only what the test needs (`initializePbApi`, `createSpinner`, …). +- Assert `CliError` / exit behaviour where relevant; cover success and failure paths. +- Do not commit secrets or real credential files. + +## Adding or changing a command + +1. Implement `src/cmds/.ts` with JSDoc on the exported function. +2. Register in `src/register-cli-commands.ts` (`addApiCredentialOptions` / `addSpinnerVerboseOptions`, `withCommandContext`, help examples). +3. Export from `src/cmds/index.ts` if needed elsewhere. +4. Update `src/completion.ts` when the public surface changes. +5. Add `test/cmds/.test.ts`. +6. Run `npm run docs` so `GENERATED_README.md` matches Commander. +7. Prefer shared runners in `src/utils/command-runners.ts` over new spinner boilerplate. +8. User-facing errors: `throw new CliError(ERROR_CODES.*, '…')` and update `EXIT_CODE_BY_CLI_CODE` in `src/utils/cli-errors.ts` if you add a code. + +**Do not re-enable** hidden `ai` / `bank` / `register` / `login` without an explicit product decision (they throw `COMMAND_DISABLED`). + +PR hygiene: one logical change per PR; include tests; avoid unrelated refactors. + +## Documentation + +| Doc | Audience | +|-----|----------| +| [README.md](./README.md) | Users (Divio: tutorials / how-to / reference / explanation) | +| [GENERATED_README.md](./GENERATED_README.md) | Generated command/option reference | +| [DISTRIBUTION.md](./DISTRIBUTION.md) | Binaries, Homebrew, deb/snap, formula notes | +| [skills/ipb/](./skills/ipb/) | Agents operating the installed CLI | +| This file | Contributors | + +After changing Commander definitions: + +```sh +npm run docs +``` + +Commit the updated `GENERATED_README.md` with the command change. + +User-facing README download examples should use the same version as `package.json` when you cut a release (see [Version bumps](#version-bumps)). + +## Demo GIFs (VHS tapes) + +```sh +IPB_NO_UPDATE_CHECK=1 npm run tapes +# runs scripts/tapes.sh — requires VHS and a built CLI +``` + +Regenerate assets under `assets/` when UX of recorded commands changes meaningfully. + +## Git hooks + +Husky **pre-push** runs: + +```sh +npm run verify:ci # build + test:run + bundle +``` + +Fix failures locally before pushing. Do not use `--no-verify` unless you have a documented emergency reason. + +## Pull requests + +1. Branch from an up-to-date `main`. +2. Keep the diff focused; mention user-visible behaviour in the PR body. +3. Ensure `npm run ci` (or at least `npm run test:run` + `npm run lint`) passes. +4. Update README / GENERATED_README / CONTRIBUTING when behaviour or contributor workflows change. +5. Link related issues. + +Suggested PR checklist: + +- [ ] Tests added or updated +- [ ] `npm run lint` / `lint:md` clean when you touched code or markdown +- [ ] `npm run docs` if Commander options/commands changed +- [ ] No secrets in the diff +- [ ] Version/docs URLs updated only as part of an intentional release bump + +## Version bumps + +The CLI version is **sourced from `package.json`**: + +- Runtime (`node bin/index.js`): `createRequire` → `../package.json` +- Standalone binaries: esbuild `define` injects `__IPB_PACKAGE_VERSION__` at bundle time + +You do **not** hardcode the version in `src/index.ts`. + +### SemVer guidance + +| Change | Bump | +|--------|------| +| Breaking CLI/API behaviour for users | major | +| New commands/flags, non-breaking improvements | minor | +| Bug fixes, docs, dependency patches | patch | + +### Checklist when bumping (example `0.8.4` → `0.8.5`) + +1. Update `"version"` in [`package.json`](./package.json) (lockfile version field updates on install). +2. Update user-facing version strings in docs that pin a release URL, for example README download links (`v0.8.4` → `v0.8.5`) and any examples in DISTRIBUTION / Ubuntu docs you maintain. +3. Update Homebrew formula version/URL/sha when you publish that channel (see DISTRIBUTION.md). +4. Rebuild and confirm: + + ```sh + npm run build + node bin/index.js --version # must print the new version + npm run bundle + # optional: npm run pkg:macos|linux and run the binary --version + ``` + +5. Commit with a clear message, for example `chore: release 0.8.5`. +6. Tag and push (maintainers): + + ```sh + git tag v0.8.5 + git push origin main + git push origin v0.8.5 + ``` + +Tag shape must be `v*.*.*` to trigger release workflows. + +### What not to do + +- Do not bump version in random source files hoping `--version` changes. +- Do not tag before `package.json` matches the tag. +- Do not leave README binary URLs on an old version after a public release. + +## Releasing + +Maintainers typically: + +1. Complete the [version bump checklist](#version-bumps). +2. Merge to `main`. +3. Push tag `vX.Y.Z`. + +Automated workflows (see `.github/workflows/`): + +| Workflow | Trigger | Purpose | +|----------|---------|---------| +| `node.js.yml` | push/PR | Build + test; packaging smoke | +| `publish.yml` | tag `v*.*.*` | `npm publish` | +| `release.yml` | tag `v*.*.*` | Build platform binaries + GitHub Release assets | +| `snap-release.yml` | (see workflow) | Snap packaging | + +After the GitHub Release exists, update Homebrew / distro packages as described in [DISTRIBUTION.md](./DISTRIBUTION.md) and [UBUNTU_DISTRIBUTION.md](./UBUNTU_DISTRIBUTION.md). + +Dry-run package contents before a real publish: + +```sh +npm run build +npm pack --dry-run +``` + +Published npm package includes the `bin/` folder (`files` in package.json); `package.json` is always included by npm. + +## Useful environment variables for contributors + +| Variable | Use | +|----------|-----| +| `DEBUG` / `--verbose` | Verbose CLI logging | +| `IPB_MOCK_APIS` | Prefer mock API clients when available | +| `IPB_NO_UPDATE_CHECK` | Skip registry version checks | +| `NO_COLOR` / `FORCE_COLOR` | Colour control | +| `EDITOR` | `ipb config edit` | +| `REJECT_UNAUTHORIZED` | TLS behaviour for custom hosts (use carefully) | + +List all documented env vars: + +```sh +node bin/index.js env-list +``` + +## Where to get help + +- Open a GitHub issue for bugs and feature ideas +- User how-tos: [README.md](./README.md) +- Packaging: [DISTRIBUTION.md](./DISTRIBUTION.md) +- Historical refactor notes: [IMPROVEMENT_PLAN.md](./IMPROVEMENT_PLAN.md) (status doc, not a required checklist) diff --git a/README.md b/README.md index 9192f81..c316909 100644 --- a/README.md +++ b/README.md @@ -1,1206 +1,485 @@ # Investec Programmable Banking CLI -Allows you to deploy your code directly to your card. It also includes an emulator to test your code locally. +Deploy programmable card code, simulate transactions locally, and manage Investec accounts from the terminal. Binary name: `ipb`. ---- - -## 🌟 Community-Powered Repository 🌟 - -This repository is crafted with ❤️ by our talented community members. It's a space for everyone to use, contribute to, and share. While it aligns with the spirit of our community, please note that this repo is not directly endorsed or supported by Investec. Always exercise caution and discretion when using or contributing to community-driven projects. - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![NPM Version](https://img.shields.io/npm/v/investec-ipb) ---- - -## Table of Contents - -- [Installation](#installation) -- [Configuration](#configuration) - - [Environment Variables](#environment-variables) - - [Configuration Profiles](#configuration-profiles) -- [Usage](#usage) - - [Confirmation for Destructive Operations](#confirmation-for-destructive-operations) - - [Cards](#cards) - - [Deploy](#deploy) - - [Fetching Execution Logs](#fetching-execution-logs) - - [Run - Local Simulation](#run---local-simulation) - - [New Project](#new-project) - - [Enable and Disable Code](#enable-and-disable-code) - - [Countries](#countries) - - [Currencies](#currencies) - - [Merchants](#merchants) - - [Fetch Code](#fetch-code) - - [Upload Code](#upload-code) - - [Fetch Environment Variables](#fetch-environment-variables) - - [Upload Environment Variables](#upload-environment-variables) - - [Fetch Published Code](#fetch-published-code) - - [Publish Code](#publish-code) - - [Simulate Code](#simulate-code) - - [Accounts](#accounts) - - [Balances](#balances) - - [Transfer](#transfer) - - [Pay](#pay) - - [Transactions](#transactions) - - [Beneficiaries](#beneficiaries) -- [Config](#config) -- [Error Codes](#error-codes) -- [Development](#development) -- [Testing](#testing) -- [Contributing](#contributing) -- [License](#license) -- [Contact](#contact) -- [Acknowledgments](#acknowledgments) -- [Related Projects](#related-projects) +Community-maintained project aligned with the Investec Programmable Banking community. Not officially endorsed or supported by Investec—use and contribute with care. --- -## Installation +## Documentation map -### npm (Recommended - requires Node.js) +This README follows [Divio’s documentation system](https://documentation.divio.com/): pick the section that matches what you need. -Before installing, [download and install Node.js](https://nodejs.org/en/download/) (version 24 or higher). +| I want to… | Go to | +|------------|--------| +| Learn by doing (first successful flow) | [Tutorials](#tutorials) | +| Solve a specific task | [How-to guides](#how-to-guides) | +| Look up a command, flag, or error code | [Reference](#reference) | +| Understand why the CLI works this way | [Explanation](#explanation) | +| Contribute or release | [CONTRIBUTING.md](./CONTRIBUTING.md) | -To install or upgrade the CLI, run the following command: - -```sh -npm install -g investec-ipb -``` - -On Windows, you may need to set your execution policy to allow running scripts. You can do this by running the following command in PowerShell as an administrator: - -```sh -Set-ExecutionPolicy Unrestricted -Scope CurrentUser -``` +Full option lists for every command: [GENERATED_README.md](./GENERATED_README.md) (or run `ipb --help` / `ipb docs`). -### Homebrew (macOS/Linux - no Node.js required) - -Install via Homebrew for a standalone binary (no Node.js installation needed): - -```sh -brew tap devinpearson/ipb -brew install ipb -``` +--- -Or install directly: +## Tutorials -```sh -brew install devinpearson/ipb/ipb -``` +Learning-oriented: follow in order. You will install the CLI, save credentials, list a card, scaffold a project, simulate locally, deploy, and fetch logs. -### Direct Download (no Node.js required) +### Your first card flow -Download pre-built binaries from [GitHub Releases](https://github.com/devinpearson/ipb/releases). +**Time:** about 10 minutes. **You need:** Node.js 24+ (or a standalone binary), Investec API credentials from the [Developer Portal](https://developer.investec.com), and a programmable card. -**macOS:** +#### 1. Install ```sh -# Apple Silicon (M1/M2/M3) -curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.3/ipb-macos-arm64 -o ipb -chmod +x ipb -sudo mv ipb /usr/local/bin/ - -# Intel -curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.3/ipb-macos-x64 -o ipb -chmod +x ipb -sudo mv ipb /usr/local/bin/ -``` - -**Linux:** - -**Ubuntu/Debian (.deb package):** - -```sh -# Download .deb package -wget https://github.com/devinpearson/ipb/releases/download/v0.8.3/ipb_0.8.3_amd64.deb - -# Install -sudo dpkg -i ipb_0.8.3_amd64.deb -sudo apt-get install -f # Install dependencies if needed +npm install -g investec-ipb +ipb --version ``` -**Direct Binary:** +Other install methods: [How to install](#how-to-install). -```sh -# x64 -curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.3/ipb-linux-x64 -o ipb -chmod +x ipb -sudo mv ipb /usr/local/bin/ - -# ARM64 -curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.3/ipb-linux-arm64 -o ipb -chmod +x ipb -sudo mv ipb /usr/local/bin/ -``` +#### 2. Save credentials -**Ubuntu PPA (if available):** +Get your client ID, client secret, and API key from the [API quick start guide](https://investec.gitbook.io/programmable-banking-community-wiki/get-started/api-quick-start-guide/how-to-get-your-api-keys). ```sh -sudo add-apt-repository ppa:your-launchpad-id/ipb -sudo apt update -sudo apt install ipb +ipb config --client-id --client-secret --api-key ``` -**Windows:** -Download `ipb-win-x64.exe` from the [releases page](https://github.com/devinpearson/ipb/releases), rename it to `ipb.exe`, and add it to your PATH. - -For more distribution options, see [DISTRIBUTION.md](./DISTRIBUTION.md). - -### Shell Autocomplete - -The CLI supports shell autocomplete for bash and zsh, making it easier to discover commands and options. - -**Bash:** - -```sh -# Install for all users (requires sudo) -sudo ipb completion bash > /etc/bash_completion.d/ipb - -# Or install for current user only -mkdir -p ~/.bash_completion.d -ipb completion bash > ~/.bash_completion.d/ipb -echo "source ~/.bash_completion.d/ipb" >> ~/.bashrc - -# For current session only -source <(ipb completion bash) -``` +Prefer credential files over putting secrets in environment variables. See [Explanation: credentials and secrets](#credentials-and-secrets). -**Zsh:** +#### 3. List your cards ```sh -# Install completion script -mkdir -p ~/.zsh/completions -ipb completion zsh > ~/.zsh/completions/_ipb - -# Add to ~/.zshrc -fpath=(~/.zsh/completions $fpath) -autoload -U compinit && compinit +ipb cards ``` -After installation, restart your terminal or source your shell configuration file. You can then use `Tab` to autocomplete commands, options, and file paths. - ---- +Note a **card key** for later steps (`-c`). -## Configuration - -You can access your client ID, client secret, and API key from the Investec Developer Portal. More information on how to access your keys can be found on the [Investec Developer Community Wiki](https://investec.gitbook.io/programmable-banking-community-wiki/get-started/api-quick-start-guide/how-to-get-your-api-keys). +![cards command](assets/cards.gif) -To configure the CLI, run the following command: +#### 4. Scaffold a project ```sh -ipb config --client-id --client-secret --api-key +ipb new my-card-app +cd my-card-app ``` -**⚠️ Security Note:** While the CLI supports environment variables, it's recommended to use credential files for secrets (see [Security Best Practices](#security-best-practices) below). Environment variables can be leaked in process lists, logs, and CI/CD configurations. - -If you want to set up specific environments for your code, you can set the environment variables in a `.env` file in the root of your project: +Optional templates: `--template default` or `--template petro`. -```env -INVESTEC_HOST=https://openapi.investec.com -INVESTEC_CLIENT_ID=your-client-id -# ⚠️ SECURITY WARNING: Secrets in .env files can be leaked -# Consider using credential files instead: ipb config --client-secret --api-key -INVESTEC_CLIENT_SECRET=your-client-secret -INVESTEC_API_KEY=your-api-key -``` +![new command](assets/new.gif) -### Environment Variables +#### 5. Simulate locally (no API keys required for this step) -The CLI supports several environment variables that can be set in your shell or `.env` file. To see all supported environment variables with detailed descriptions, run: +Amount is in **cents**: ```sh -ipb env-list +ipb run -f main.js -e prod --amount 60000 --currency ZAR --mcc 0000 \ + --merchant "Test Merchant" --city "Cape Town" --country ZA ``` -This command displays: - -- **API Credentials**: `INVESTEC_HOST`, `INVESTEC_CLIENT_ID`, `INVESTEC_CLIENT_SECRET`, `INVESTEC_API_KEY`, `INVESTEC_CARD_KEY` -- **Development**: `DEBUG` -- **Security**: `REJECT_UNAUTHORIZED` - -#### Standard CLI Environment Variables - -The CLI follows standard CLI conventions and respects these environment variables: - -- **`NO_COLOR`**: Disable colored output. Set to any value to disable colors. - - ```sh - NO_COLOR=1 ipb accounts - ``` - -- **`FORCE_COLOR`**: Force colored output even when piping. Set to any value to enable colors. - - ```sh - FORCE_COLOR=1 ipb accounts | cat - ``` - -- **`DEBUG`**: Enable verbose/debug output. Set to any value to enable verbose mode (equivalent to `--verbose` flag). - - ```sh - DEBUG=1 ipb accounts - # Or - DEBUG=true ipb deploy -f main.js - ``` - -- **`PAGER`**: Specify pager for long output. Defaults to `less` if not set. - - ```sh - PAGER=more ipb transactions - ``` - -- **`LINES`** and **`COLUMNS`**: Terminal dimensions for table formatting (automatically detected if not set). - -- **`TMPDIR`**: Temporary directory for temporary files. Defaults to system temp directory (`/tmp` on Unix, `%TEMP%` on Windows) if not set. - - ```sh - TMPDIR=/custom/tmp ipb - ``` - - Note: The CLI uses Node.js `os.tmpdir()` which automatically respects `TMPDIR`. Atomic file operations (like credential writes) use the same directory as the target file to ensure atomicity. - -- **`EDITOR`**: Editor to use for editing configuration files. Defaults to `nano` on Unix, `notepad.exe` on Windows. - - ```sh - EDITOR=vim ipb config edit - EDITOR="code --wait" ipb config edit # VS Code - ``` - - Used by `ipb config edit` command to open credentials files in your preferred editor. - -- **`TERM`**: Terminal type for capability detection. The CLI automatically detects terminal capabilities and falls back to ASCII alternatives when Unicode/emoji are not supported. - - ```sh - TERM=dumb ipb accounts # Uses ASCII fallbacks - TERM=xterm-256color ipb accounts # Uses emojis if supported - ``` +![run command](assets/run.gif) - The CLI checks `TERM`, `TERMINFO`, and `TERMCAP` environment variables to determine if the terminal supports Unicode and emoji characters. Emojis are automatically replaced with ASCII equivalents (e.g., `💳` → `[CARD]`) when the terminal doesn't support them. +#### 6. Deploy to the card -You can also get structured output: +`deploy` uploads (and can publish) code. You will be asked to confirm unless you pass `--yes`. ```sh -ipb env-list --json -ipb env-list --yaml --output env-vars.yaml +ipb deploy -f main.js -c ``` -### Security Best Practices - -#### ⚠️ Important: Secret Handling - -For security reasons, the CLI **recommends storing secrets in credential files rather than environment variables**. While the CLI supports environment variables for convenience, they pose security risks: - -**Why credential files are more secure:** - -- Environment variables can be leaked in: - - Process lists (`ps`, `top`, `htop`) - - System logs - - CI/CD configuration files (GitHub Actions, GitLab CI, etc.) - - Shell history files - - Debug output and error messages -- Credential files are stored with restricted permissions (`600`) and in a secure location (`~/.ipb/.credentials.json`) - -**The CLI will automatically warn you if:** - -- Secrets are detected in environment variables AND -- You're running in verbose mode (`--verbose` or `DEBUG=1`) OR -- You're in a non-interactive environment (CI/CD, scripts, etc.) +![deploy command](assets/deploy.gif) -**Recommended approach:** +#### 7. Fetch execution logs ```sh -# Store secrets in credential files (recommended) -ipb config --client-id --client-secret --api-key - -# Or use profiles for multiple environments -ipb config --profile production --client-id --client-secret --api-key -ipb config --profile staging --client-id --client-secret --api-key -ipb config profile set production # Set active profile +ipb logs -f executions.json -c ``` -**When environment variables are acceptable:** - -- Development/testing environments (with awareness of risks) -- Temporary use cases where credential files are not practical -- When you understand the security implications - -**Note:** The CLI still supports environment variables for backward compatibility, but you should be aware of the security implications. The CLI follows [clig.dev](https://clig.dev/) guidelines which recommend against reading secrets from environment variables. +![logs command](assets/logs.gif) -**Priority Order** (highest to lowest): +You now have a working loop: edit → `ipb run` → `ipb deploy` → `ipb logs`. Next: [How-to guides](#how-to-guides) for profiles, env files, accounts, and automation. -1. Command line options (e.g., `--client-id`, `--api-key`) -2. Configuration profile (if `--profile` is specified or active profile is set) -3. Environment variables -4. Credentials file (`~/.ipb/.credentials.json`) +--- -You also have the option to specify the host, client ID, client secret, API key, and card ID when calling each command. These will override the configuration set in the `.env` file and your credential file: +## How-to guides -```sh -ipb deploy -f -e -c --host --client-id --client-secret --api-key -``` - -You can also create your own `.credentials.json` file and store and access it in a location you prefer. This file should be in the following format: +Goal-oriented recipes. For every flag, use `ipb --help`. -```json -{ - "client_id": "your-client-id", - "client_secret": "your-client-secret", - "api_key": "your-api-key", - "card_id": "your-card-id" -} -``` +### How to install -To configure the CLI using a credentials file, run the following command: +**npm (recommended if you already use Node.js 24+):** ```sh -ipb cards --credentials-file +npm install -g investec-ipb ``` -The card ID is optional and can be set when calling each command. If you specify a card when calling a command, it will override the card ID set in the configuration. - -### Configuration Profiles - -The CLI supports multiple configuration profiles, making it easy to switch between different environments (production, staging, development, etc.) without manually changing credentials. - -**Creating Profiles:** - -Save credentials to a specific profile: +On Windows PowerShell (if scripts are blocked): ```sh -# Create a production profile -ipb config --profile production --client-id --client-secret --api-key - -# Create a staging profile -ipb config --profile staging --client-id --client-secret --api-key - -# Update an existing profile (adds or updates only the specified fields) -ipb config --profile production --card-key +Set-ExecutionPolicy Unrestricted -Scope CurrentUser ``` -**Using Profiles:** - -Use a profile with any command using the `--profile` option: +**Homebrew (standalone binary, no Node.js):** ```sh -# Deploy to production -ipb deploy --profile production -f main.js -c card-123 - -# List cards from staging -ipb cards --profile staging - -# Check balances using a specific profile -ipb balances acc-123 --profile production +brew tap devinpearson/ipb +brew install ipb ``` -**Managing Profiles:** +**Direct download:** binaries on [GitHub Releases](https://github.com/devinpearson/ipb/releases). -List all available profiles: +macOS: ```sh -ipb config profile list -``` - -This shows all profiles with the active profile marked: +# Apple Silicon +curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.4/ipb-macos-arm64 -o ipb +chmod +x ipb +sudo mv ipb /usr/local/bin/ -```text -Available profiles: - - development - - production (active) - - staging +# Intel +curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.4/ipb-macos-x64 -o ipb +chmod +x ipb +sudo mv ipb /usr/local/bin/ ``` -Set a default active profile (used when `--profile` is not specified): +Linux (.deb): ```sh -ipb config profile set production +wget https://github.com/devinpearson/ipb/releases/download/v0.8.4/ipb_0.8.4_amd64.deb +sudo dpkg -i ipb_0.8.4_amd64.deb +sudo apt-get install -f ``` -Show the currently active profile: +Linux binary: ```sh -ipb config profile show -``` - -Delete a profile: - -```sh -ipb config profile delete staging +curl -L https://github.com/devinpearson/ipb/releases/download/v0.8.4/ipb-linux-x64 -o ipb +# or: ipb-linux-arm64 +chmod +x ipb +sudo mv ipb /usr/local/bin/ ``` -**Profile Storage:** - -- Profiles are stored in `~/.ipb/profiles/.json` -- The active profile is stored in `~/.ipb/active-profile.json` -- All profile files use secure permissions (read/write for owner only) -- Profiles can contain: `clientId`, `clientSecret`, `apiKey`, `cardKey`, `host` +Windows: download `ipb-win-x64.exe`, rename to `ipb.exe`, add to `PATH`. -**Profile Priority:** +More packaging options: [DISTRIBUTION.md](./DISTRIBUTION.md). -When using `--profile`, the profile credentials are loaded first, then command-line options override specific values: +### How to configure credentials and profiles ```sh -# Profile credentials are loaded, but --api-key overrides the profile's API key -ipb deploy --profile production --api-key different-key -f main.js -``` - -**Example Workflow:** +# Default credentials (~/.ipb/.credentials.json, mode 600) +ipb config --client-id --client-secret --api-key -```sh -# 1. Set up profiles for different environments -ipb config --profile production --client-id prod-id --client-secret prod-secret --api-key prod-key -ipb config --profile staging --client-id stage-id --client-secret stage-secret --api-key stage-key +# Optional card key / host — see ipb config --help +ipb config --card-key -# 2. Set production as default +# Named profiles +ipb config --profile production --client-id --client-secret --api-key +ipb config --profile staging --client-id --client-secret --api-key ipb config profile set production - -# 3. Use default profile (production) -ipb deploy -f main.js -c card-123 - -# 4. Use staging profile explicitly -ipb deploy --profile staging -f main.js -c card-456 - -# 5. Override a specific credential -ipb deploy --profile production --card-key different-card -f main.js -``` - ---- - -## Usage - -### Confirmation for Destructive Operations - -Several commands that perform destructive operations (deploy, publish, disable, transfer, pay) require interactive confirmation before execution. This helps prevent accidental operations that could affect your code or financial transactions. - -**Commands requiring confirmation:** - -- `deploy` - Overwrites existing code on a card -- `publish` - Activates code on a card -- `disable` - Deactivates code on a card -- `transfer` - Transfers money between accounts -- `pay` - Makes a payment to a beneficiary - -**Skip confirmation with `--yes` flag:** - -For automation and CI/CD pipelines, you can use the `--yes` flag to skip confirmation prompts: - -```sh -ipb deploy -f main.js -c card-123 --yes -ipb publish -f app.js --code-id code-123 -c card-456 --yes -ipb transfer acc-123 acc-456 100.50 "Payment" --yes -ipb pay acc-123 ben-456 250.00 "Payment" --yes -ipb disable -c card-123 --yes -``` - -**Note:** In non-interactive environments (when output is piped), the `--yes` flag is required for destructive operations to proceed. - -### Cards - -To get a list of your cards with card keys, card number, and whether the card is enabled for card code, run the following command: - -```sh -ipb cards +ipb config profile list +ipb config profile show ``` -This command retrieves detailed information about your cards, including their unique identifiers and status. It is useful for managing multiple cards and ensuring the correct card is targeted for operations. - -![cards command](assets/cards.gif) - -### Deploy - -Deploy your code directly to your card. This command allows you to specify environment variables and target a specific card for deployment. For environment variables, you can set them in a `.env` file in the root of your project. Name your environments such as `.env.prod` or `.env.dev` and specify the environment when running the command. - -**⚠️ This command requires confirmation** as it will overwrite any existing code on the card. - -To deploy code to your card, run the following command: +Use a profile on any command: ```sh -ipb deploy -f -e -c +ipb cards --profile staging +ipb deploy --profile production -f main.js -c ``` -You will be prompted to confirm before the deployment proceeds. To skip the confirmation prompt (useful for automation), use the `--yes` flag: +Edit in your editor (`EDITOR`, default `nano` / `notepad.exe`): ```sh -ipb deploy -f -e -c --yes +ipb config edit +ipb config edit --profile production ``` -This command ensures that your code is uploaded securely to the specified card. It also supports environment-specific configurations to avoid accidental uploads of sensitive data. - -![deploy command](assets/deploy.gif) - -### Fetching Execution Logs - -Fetch execution logs and save them to a file. The output is in JSON format, and the file will be overwritten if it already exists. This command is essential for debugging and monitoring the behavior of your deployed code. - -To fetch execution logs, run the following command: +Custom credentials file: ```sh -ipb logs -f -c +ipb cards --credentials-file /path/to/credentials.json ``` -This command retrieves logs for the specified card and saves them to the provided filename, such as `executions.json` or `logs.json`. It helps you analyze the execution flow and identify any issues. - -![logs command](assets/logs.gif) - -### Run - Local Simulation - -Simulate your code locally by specifying transaction details as arguments. The amount is in cents, and the currency is the ISO 4217 currency code. This command does not require an Investec account or API keys, as it runs entirely locally. - -To run a transaction against your local files, use the following command: +### How to deploy code and manage card environments ```sh -ipb run -f main.js -e prod --amount 60000 --currency ZAR --mcc 0000 --merchant "Test Merchant" --city "Test City" --country ZA -``` - -This command is ideal for testing your code in a controlled environment before deploying it to a card. It provides detailed logs of the transaction and execution process. - -![run command](assets/run.gif) +# One-shot deploy (upload + publish path; confirms by default) +ipb deploy -f main.js -e prod -c +ipb deploy -f main.js -c --yes -### New Project +# Split steps +ipb upload -f main.js -c +ipb publish -f main.js --code-id -c -To scaffold a new project, run the following command: +# Environment variables on the card +ipb env -f env.json -c +ipb upload-env -f env.json -c -```sh -ipb new --template +# Download code from the card +ipb fetch -f backup.js -c +ipb published -f published.js -c ``` -The `template` option is optional and can be set to `default` or `petro` to create a project using one of the predefined templates. This command helps you quickly set up a project structure tailored to your needs. - -![new command](assets/new.gif) - -### Enable and Disable Code - -To enable or disable code on your card, use the following commands: - -Enable code: +Use `.env.` locally and pass `-e ` when the command supports it (for example `deploy` / `run`). -```sh -ipb enable -c -``` +![upload command](assets/upload.gif) -Disable code: +### How to simulate transactions -**⚠️ This command requires confirmation** as it will deactivate the programmable code on your card. +**Local emulator** (no Investec account required): ```sh -ipb disable -c +ipb run -f main.js -e prod --amount 60000 --currency ZAR --mcc 0000 \ + --merchant "Test Merchant" --city "Cape Town" --country ZA ``` -You will be prompted to confirm before disabling the code. To skip the confirmation prompt, use the `--yes` flag: +**Online simulator** (uses API / card context and remote env): ```sh -ipb disable -c --yes +ipb simulate -f main.js -c --amount 60000 --currency ZAR --mcc 0000 \ + --merchant "Test Merchant" --city "Cape Town" --country ZA ``` -These commands allow you to control whether the programmable code is active on your card. This is useful for testing or temporarily disabling functionality. - -![toggle command](assets/toggle.gif) - -### Countries - -Retrieve a list of countries that can be used in the card code: +Reference data for MCC / country / currency values: ```sh ipb countries -``` - -This command provides a list of supported countries, which can be useful for setting up transactions or merchant details. - -### Currencies - -Retrieve a list of currencies that can be used in the card code: - -```sh ipb currencies -``` - -This command provides a list of supported currencies, including their ISO 4217 codes, for use in transactions. - -### Merchants - -Retrieve a list of merchants that can be used in the card code: - -```sh ipb merchants ``` -This command provides merchant details, such as names and categories, to help you simulate or configure transactions. - -### Fetch Code - -To fetch the code saved on the card, run the following command: +### How to enable or disable code on a card ```sh -ipb fetch -f -c +ipb enable -c +ipb disable -c # confirms +ipb disable -c --yes ``` -This command downloads the code currently saved on the card to a local file for review or backup. - -![fetch command](assets/fetch.gif) - -### Upload Code - -To upload code to the card's saved code, run the following command: - -```sh -ipb upload -f -c -``` - -This command uploads your code to the card, making it available for execution. - -![upload command](assets/upload.gif) - -### Fetch Environment Variables - -To fetch the environment variables saved on the card, run the following command: - -```sh -ipb env -f -c -``` - -This command downloads the environment variables from the card to a local file for review or modification. - -![env command](assets/env.gif) - -### Upload Environment Variables - -To upload environment variables to the card, run the following command: - -```sh -ipb upload-env -f -c -``` - -This command uploads environment variables to the card, allowing you to configure its runtime environment. - -![upload-env command](assets/upload-env.gif) - -### Fetch Published Code - -To fetch the published code saved on the card, run the following command: - -```sh -ipb published -f -c -``` - -This command downloads the published version of the code from the card to a local file. - -![published command](assets/published.gif) - -### Publish Code - -To publish code to the card, you will need the `codeId` returned when saving the code using the upload command. - -**⚠️ This command requires confirmation** as it will activate the code on your card. - -Run the following command: - -```sh -ipb publish -f --code-id -c -``` - -You will be prompted to confirm before publishing. To skip the confirmation prompt, use the `--yes` flag: - -```sh -ipb publish -f --code-id -c --yes -``` - -This command publishes the uploaded code, making it the active version on the card. - -![publish command](assets/publish.gif) - -### Simulate Code - -Use the online simulator to test your code without deploying it to the card. This is similar to the `run` command but uses the online simulator instead of the local emulator. Be aware that it will use your online environment and not your local environment. - -```sh -ipb simulate -f main.js -c --amount 60000 --currency ZAR --mcc 0000 --merchant "Test Merchant" --city "Test City" --country ZA -``` - -This command is ideal for testing your code in a production-like environment before deploying it to the card. - -![simulate command](assets/simulate.gif) - -### Accounts +![toggle command](assets/toggle.gif) -Get a list of your accounts: +### How to work with accounts and payments ```sh ipb accounts -``` - -This command retrieves all your Investec accounts linked to your credentials. - -### Balances - -Get balances for a specific account: - -```sh ipb balances +ipb transactions +ipb beneficiaries ``` -This command fetches the balance for the given account ID. - -### Transfer - -Transfer between your accounts: - -**⚠️ This command requires confirmation** as it will transfer money between your accounts. +Money movement **requires confirmation** (or `--yes` for automation): ```sh ipb transfer +ipb pay ``` -A summary of the transfer will be displayed, and you will be prompted to confirm before proceeding. To skip the confirmation prompt, use the `--yes` flag: - -```sh -ipb transfer --yes -``` - -Transfers the specified amount (in rands, e.g. 100.00) from one account to another with a reference. +Amounts for transfer/pay are in **rands** (for example `100.50`), not cents. -### Pay +### How to install shell completion -Pay a beneficiary from your account: - -**⚠️ This command requires confirmation** as it will make a payment from your account. +**Bash:** ```sh -ipb pay +mkdir -p ~/.bash_completion.d +ipb completion bash > ~/.bash_completion.d/ipb +echo "source ~/.bash_completion.d/ipb" >> ~/.bashrc ``` -A summary of the payment will be displayed, and you will be prompted to confirm before proceeding. To skip the confirmation prompt, use the `--yes` flag: +**Zsh:** ```sh -ipb pay --yes +mkdir -p ~/.zsh/completions +ipb completion zsh > ~/.zsh/completions/_ipb +# In ~/.zshrc: +# fpath=(~/.zsh/completions $fpath) +# autoload -U compinit && compinit ``` -Pays a beneficiary from your account with the specified amount and reference. - -### Transactions - -Get transactions for a specific account: +### How to automate safely ```sh -ipb transactions -``` - -Fetches the transaction history for the given account ID. +# Machine-readable output +ipb cards --json +ipb accounts --json | jq . -### Beneficiaries +# Skip confirms only when intentional +ipb deploy -f main.js -c --yes -Get your list of beneficiaries: - -```sh -ipb beneficiaries +# Quiet / debug +ipb accounts --no-spinner +ipb accounts --verbose +# or: DEBUG=1 ipb accounts ``` -Lists all beneficiaries linked to your Investec profile. +When stdout is piped, the CLI favours structured output and turns spinners off. Destructive commands need `--yes` in non-interactive use. -### Config +Handle exit codes in scripts: -Set authentication credentials for the CLI: - -```sh -# Save to default credentials -ipb config --client-id --client-secret --api-key - -# Save to a profile -ipb config --profile production --client-id --client-secret --api-key +```bash +if ipb deploy -f main.js -c "$CARD" --yes; then + echo "ok" +else + echo "failed with exit $?" +fi ``` -You can also set **card key** and **host** on the credentials record using additional options (see `ipb config --help`). - -**Profile Management:** +See [Exit codes](#exit-codes) and [Error codes](#error-codes). -The `config` command also supports managing configuration profiles: - -```sh -# List all profiles -ipb config profile list +--- -# Set active profile -ipb config profile set production +## Reference -# Show active profile -ipb config profile show +Information-oriented lookup. Authoritative flags: `ipb --help` or [GENERATED_README.md](./GENERATED_README.md). -# Delete a profile -ipb config profile delete staging +### Command map -# Edit credentials in your editor -ipb config edit -ipb config edit --profile production -``` +| Command | Purpose | +|---------|---------| +| `cards` (`c`) | List programmable cards | +| `config` (`cfg`) | Save credentials; `profile` / `edit` subcommands | +| `new` | Scaffold a local project | +| `run` (`r`) | Local transaction simulation | +| `simulate` | Online simulator | +| `deploy` (`d`) | Deploy code to a card | +| `upload` (`up`) / `publish` (`pub`) | Upload or publish code | +| `fetch` (`f`) / `published` | Download saved or published code | +| `env` / `upload-env` | Card environment variables | +| `logs` (`log`) | Execution logs | +| `enable` / `disable` | Toggle code on a card | +| `accounts` (`acc`) / `balances` (`bal`) / `transactions` (`tx`) | Account data | +| `beneficiaries` / `transfer` / `pay` | Beneficiaries and payments | +| `countries` / `currencies` / `merchants` | Reference data | +| `completion` / `docs` / `env-list` | Shell completion, docs dump, env catalogue | -**Editing Credentials:** +These commands are **disabled** and return an error: `ai`, `bank`, `register`, `login`. -You can edit credentials files directly in your preferred editor using the `edit` subcommand: +### Shared options (most API commands) -```sh -# Edit default credentials -ipb config edit +- Auth: `--client-id`, `--client-secret`, `--api-key`, `--host`, `--credentials-file`, `--profile` +- Output: `--json`, `--yaml`, `--output `, `-v` / `--verbose` +- Spinner: `--no-spinner` (preferred); `-s` / `--spinner` is deprecated +- Destructive: `--yes` where supported -# Edit a specific profile -ipb config edit --profile production -``` +### Environment variables -The command respects the `EDITOR` environment variable. If not set, it defaults to `nano` on Unix systems and `notepad.exe` on Windows. +List everything the CLI documents: ```sh -# Use a specific editor -EDITOR=vim ipb config edit -EDITOR="code --wait" ipb config edit # VS Code +ipb env-list +ipb env-list --json ``` -For more details, see the [Configuration Profiles](#configuration-profiles) section above. - ---- - -## Exit Codes - -The CLI uses specific exit codes to indicate different types of errors, making it easier to handle errors in scripts and automation. All commands exit with code `0` on success. +Common categories: -### Exit Code Reference +- **API:** `INVESTEC_HOST`, `INVESTEC_CLIENT_ID`, `INVESTEC_CLIENT_SECRET`, `INVESTEC_API_KEY`, `INVESTEC_CARD_KEY` +- **Behaviour:** `DEBUG`, `REJECT_UNAUTHORIZED`, `NO_COLOR`, `FORCE_COLOR`, `EDITOR`, `PAGER`, `TMPDIR`, `IPB_NO_UPDATE_CHECK` -| Exit Code | Meaning | Description | -|------------|---------|-------------| -| `0` | Success | Command completed successfully | -| `1` | General Error | Generic error that doesn't fit other categories | -| `2` | Validation Error | Invalid input, missing required fields, or invalid arguments | -| `3` | Authentication Error | Invalid or missing credentials, authentication failures | -| `4` | File Error | File not found, file system errors, template issues | -| `5` | API Error | API request failures, server errors (5xx), deployment failures | -| `6` | Network Error | Network connection issues, timeouts, DNS failures | -| `7` | Permission Error | File permission errors, access denied | +### Exit codes -### Examples +| Exit | Meaning | +|------|---------| +| `0` | Success | +| `1` | General error | +| `2` | Validation / bad input | +| `3` | Authentication | +| `4` | File | +| `5` | API (includes rate limits) | +| `6` | Network | +| `7` | Permission | -```bash -# Success - exits with code 0 -ipb cards -echo $? # Output: 0 - -# Validation error - exits with code 2 -ipb deploy -f missing.js -echo $? # Output: 2 - -# Authentication error - exits with code 3 -ipb accounts # With invalid credentials -echo $? # Output: 3 +### Error codes -# File error - exits with code 4 -ipb deploy -f nonexistent.js -echo $? # Output: 4 -``` - -### Using Exit Codes in Scripts +Messages look like `Error (E####): …`. -You can use exit codes in shell scripts to handle different error types: - -```bash -#!/bin/bash - -if ipb deploy -f main.js; then - echo "Deployment successful!" -else - exit_code=$? - case $exit_code in - 2) echo "Validation error - check your input" ;; - 3) echo "Authentication error - check your credentials" ;; - 4) echo "File error - check file paths" ;; - 5) echo "API error - check API status" ;; - 6) echo "Network error - check your connection" ;; - 7) echo "Permission error - check file permissions" ;; - *) echo "Unknown error (code: $exit_code)" ;; - esac - exit $exit_code -fi -``` +| Code | Description | +|------|-------------| +| `E4002` | Missing API token | +| `E4003` | Missing card key | +| `E4004` | Missing environment file | +| `E4005` | Invalid credentials | +| `E4007` | Template not found | +| `E4008` | Invalid project name | +| `E4009` | Project exists | +| `E4010` | File not found | +| `E4012` | Missing account ID | +| `E4014` | Rate limit exceeded | +| `E5001` | Deploy / API operation failed | + +Quick fixes: missing card key → `ipb cards` then `-c`; bad auth → `ipb config`; missing `.env.` → create the file or change `-e`. --- -## Error Codes +## Explanation -The CLI uses standardized error codes to help identify and troubleshoot issues. When an error occurs, you'll see a message in the format: `Error (E####): [message]` +Understanding-oriented background. Skip this until you care about the “why”. -### Error Code Reference +### Credentials and secrets -| Code | Description | -|------|-------------| -| `E4002` | Missing API Token - The API token is required but was not provided | -| `E4003` | Missing Card Key - The card key is required but was not provided | -| `E4004` | Missing Environment File - The specified environment file does not exist | -| `E4005` | Invalid Credentials - The provided credentials are invalid or authentication failed | -| `E4007` | Template Not Found - The specified template does not exist | -| `E4008` | Invalid Project Name - The project name contains invalid characters | -| `E4009` | Project Exists - A project with the specified name already exists | -| `E4010` | File Not Found - The specified file does not exist | -| `E4012` | Missing Account ID - The account ID is required but was not provided | -| `E5001` | Deploy Failed - Code deployment or API operation failed | - -### Understanding Error Messages - -Error messages are displayed in the following format: - -```text -Error (E4003): card-key is required -``` - -- The error code (e.g., `E4003`) helps identify the type of error -- The message provides context-specific information about what went wrong -- Use the `--verbose` flag to get additional debugging information - -### Common Error Scenarios +Credential files under `~/.ipb/` use owner-only permissions (`600`) and atomic writes. Environment variables are convenient but can leak via process lists, CI logs, and shell history. The CLI may warn when secrets appear in the environment (especially with `--verbose` / `DEBUG` or in CI). Prefer `ipb config` and profiles for day-to-day use. -#### Missing Card Key (E4003) +**Resolution order** (highest wins): -- **Cause**: No card key provided via CLI option or credentials file -- **Solution**: Provide the card key using `-c ` or set it in your credentials file +1. Command-line options (`--api-key`, …) +2. `--profile` or the active profile +3. Environment variables +4. Default credentials file (`~/.ipb/.credentials.json`) -#### Missing Environment File (E4004) +### Destructive operations and `--yes` -- **Cause**: The specified `.env.` file does not exist -- **Solution**: Create the environment file or use a different environment name +`deploy`, `publish`, `disable`, `transfer`, and `pay` change live card state or move money. Interactive runs ask for confirmation. Automation and pipes should pass `--yes` only when the action is intentional. -#### Invalid Credentials (E4005) +### Local `run` vs online `simulate` -- **Cause**: API credentials are incorrect or expired -- **Solution**: Verify your credentials using `ipb config` or check your API keys in the Investec Developer Portal +- **`run`** uses the local emulator and local files/env—good for fast iteration offline. +- **`simulate`** hits Investec’s online simulator with your card/API context—closer to production behaviour, needs credentials. -#### File Not Found (E4010) +### Agent / automation tip -- **Cause**: The specified file path does not exist -- **Solution**: Verify the file path and ensure the file exists before running the command +Copyable skill for AI agents that operate `ipb`: [skills/ipb/](./skills/ipb/). Prefer `--json` and confirm money or deploy steps before running them. --- -## Development +## Contributing and development -For development on this library, clone the repository and run the following commands: +Issues and pull requests are welcome. For running locally, tests, docs, **version bumps**, and releases, see **[CONTRIBUTING.md](./CONTRIBUTING.md)**. ```sh git clone https://github.com/devinpearson/ipb.git cd ipb -``` - -```sh npm install -``` - -To run the CLI during development, run the following command: - -```sh -node . [command] -``` - -### Building - -To build the project: - -```sh npm run build -``` - -This compiles TypeScript to JavaScript and copies necessary files to the `bin/` directory. - -### Linting and Formatting - -The project uses Biome for linting and formatting: - -```sh -# Check for linting issues -npm run lint - -# Auto-fix linting issues -npm run lint:fix - -# Format code -npm run format - -# Check formatting -npm run format:check -``` - -### Type Checking - -To verify TypeScript types: - -```sh -npm run type-check +node bin/index.js --help ``` --- -## Testing - -The project uses [Vitest](https://vitest.dev/) for testing. The test suite includes comprehensive coverage of command functionality, error handling, and utility functions. - -### Running Tests - -Run all tests: - -```sh -npm test -``` - -Run tests in watch mode (for development): - -```sh -npm run dev -``` - -Run tests once and exit: - -```sh -npm test -- --run -``` - -Run tests with coverage: - -```sh -npm test -- --coverage -``` - -### Test Structure - -Tests are organized in the `test/` directory: - -```text -test/ -├── cmds/ # One file per command area (e.g. deploy.test.ts) -├── utils/ # Utility and integration-style unit tests -├── __mocks__/ -└── helpers.ts -``` - -### Test Patterns - -Tests follow consistent patterns for mocking and assertions: - -#### Mocking ESM Modules - -For ESM modules like `node:fs`, use `vi.hoisted()` to create mocks: - -```typescript -const mockFsPromises = vi.hoisted(() => ({ - access: vi.fn(), - readFile: vi.fn(), -})); - -vi.mock('node:fs', () => ({ - default: {}, - promises: mockFsPromises, -})); -``` - -#### Testing Error Propagation - -Since commands use centralized error handling, tests verify errors propagate correctly: - -```typescript -it('should propagate errors', async () => { - const error = new Error('API error'); - mockApi.getCards.mockRejectedValue(error); - - await expect(cardsCommand(options)).rejects.toThrow('API error'); -}); -``` - -#### Testing Command Context - -Error context is automatically attached via `withCommandContext`. Tests verify error messages include the command name: - -```typescript -// Error messages will be: "Failed to cards command: " -``` - -### Writing New Tests - -When adding tests for new commands: - -1. **Create test file** in `test/cmds/` following the naming pattern: `.test.ts` - -2. **Set up mocks**: - - ```typescript - vi.mock('../../src/index.ts', () => ({ - credentials: {}, - printTitleBox: vi.fn(), - optionCredentials: vi.fn(async (options, credentials) => credentials), - })); - - vi.mock('../../src/utils.ts', async () => { - const actual = await vi.importActual('../../src/utils.ts'); - return { - ...actual, - initializeApi: vi.fn(), - // ... other mocked utilities - }; - }); - ``` - -3. **Test success cases**: Verify command executes correctly with valid inputs - -4. **Test error cases**: Verify errors propagate correctly (no try-catch in commands) - -5. **Test edge cases**: Missing files, invalid inputs, API failures - -### Test coverage - -- Run the suite with `npm run test:run` (Vitest). Tests live under `test/cmds/` and `test/utils/`. -- When adding a command, add a matching `test/cmds/.test.ts` and follow the mocking patterns above (`vi.importActual` for `utils.ts`, mock `index.ts` credentials where needed). - ---- - -## Contributing - -Contributions are welcome! Please submit a pull request or open an issue for any suggestions or improvements. - ---- - ## License -This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. - ---- +MIT — see [LICENSE.md](LICENSE.md). ## Contact -For inquiries, please open an issue. - ---- +Open a GitHub issue for questions and bugs. ## Acknowledgments -- [Commander](https://www.npmjs.com/package/commander) -- [Chalk](https://github.com/chalk/chalk) -- [VHS](https://github.com/charmbracelet/vhs) -- [Ora](https://github.com/sindresorhus/ora) -- [NodeJS CLI Apps Best Practices](https://github.com/lirantal/nodejs-cli-apps-best-practices) -- [CLIG.dev - Command Line Interface Guidelines](https://clig.dev/) +- [Commander](https://www.npmjs.com/package/commander), [Chalk](https://github.com/chalk/chalk), [Ora](https://github.com/sindresorhus/ora), [VHS](https://github.com/charmbracelet/vhs) +- [CLIG.dev](https://clig.dev/), [Node.js CLI Apps Best Practices](https://github.com/lirantal/nodejs-cli-apps-best-practices) - [Investec Programmable Banking Community](https://developer.investec.com/za/community) +- [Divio documentation system](https://documentation.divio.com/) ---- - -## Related Projects - -Here are some related projects that complement the Investec Programmable Banking CLI: - -1. **[Banking API Simulator](https://github.com/devinpearson/programmable-banking-sim)** - A simulator for testing banking APIs in a controlled environment. - -2. **[Random Banking Data Generator](https://github.com/devinpearson/programmable-banking-faker)** - A tool for generating random banking data for testing and development purposes. - -3. **[Open Banking Point of Sales Device](https://github.com/devinpearson/programmable-banking-pos)** - A project for creating a point-of-sale device using open banking APIs. - -4. **[Card Issuer](https://github.com/devinpearson/programmable-banking-card-issuer)** - A tool for issuing programmable banking cards. - -5. **[Blockly Editor for Card Code](https://github.com/devinpearson/investec-blockly)** - A visual programming editor for creating card code using Blockly. - -6. **[HTTP Server for Card Code Emulator](https://github.com/devinpearson/investec-card-server)** - A server for running the card code emulator over HTTP. +## Related projects -7. **[Card Code Emulator Package](https://github.com/devinpearson/programmable-card-code-emulator)** - A library for emulating programmable card code. +- [Banking API Simulator](https://github.com/devinpearson/programmable-banking-sim) +- [Random Banking Data Generator](https://github.com/devinpearson/programmable-banking-faker) +- [Open Banking POS](https://github.com/devinpearson/programmable-banking-pos) +- [Card Issuer](https://github.com/devinpearson/programmable-banking-card-issuer) +- [Blockly editor for card code](https://github.com/devinpearson/investec-blockly) +- [HTTP server for card emulator](https://github.com/devinpearson/investec-card-server) +- [Card code emulator package](https://github.com/devinpearson/programmable-card-code-emulator)