# Installation

> Node >=18, global npm install, npx and bunx one-shot invocation, and the published dist/index.js binary.

- Repository: jaredpalmer/vwaffle
- GitHub: https://github.com/jaredpalmer/vwaffle
- Human docs: https://grok-wiki.com/public/docs/jaredpalmer-vwaffle-7983cb893581
- Complete Markdown: https://grok-wiki.com/public/docs/jaredpalmer-vwaffle-7983cb893581/llms-full.txt

## Source Files

- `package.json`
- `src/index.ts`
- `README.md`

---

---
title: "Installation"
description: "Node >=18, global npm install, npx and bunx one-shot invocation, and the published dist/index.js binary."
---

`vwaffle` 0.1.0 is an ESM Node CLI. `package.json` maps the `vwaffle` bin to `./dist/index.js`, declares `engines.node` as `>=18`, and publishes only `dist`, `README.md`, and `LICENSE`. The published file is a Bun-bundled Node target (`bun build src/index.ts --outdir dist --target node`) with shebang `#!/usr/bin/env node`. There are no runtime `dependencies`.

## Requirements

| Constraint | Value |
| --- | --- |
| Runtime | Node.js `>=18` (`package.json` `engines`) |
| Module format | `"type": "module"` (ESM) |
| Production npm deps | none |
| License | Apache-2.0 |
| Token for install | not required |

<ParamField body="node" type="string" required>
Declared engine: `>=18`. The CLI uses `node:` built-ins and `fetch`. npm warns on older Node unless `engine-strict` is set.
</ParamField>

<ParamField body="bin.vwaffle" type="string" required>
Published entry: `./dist/index.js`. After a global install this is the `vwaffle` command on `PATH`.
</ParamField>

<Note>
`VERCEL_TOKEN`, `--project` / `VERCEL_PROJECT_ID`, and `--team` / `VERCEL_TEAM_ID` are required only for `pull`, `plan`, and `apply`. `help`, `--version`, and `init` run without Vercel credentials.
</Note>

## Install the CLI

<Tabs>
<Tab title="Global npm">

```sh
npm install -g vwaffle
vwaffle help
```

</Tab>
<Tab title="npx (no install)">

```sh
npx vwaffle help
```

</Tab>
<Tab title="bunx (no install)">

```sh
bunx vwaffle help
```

</Tab>
</Tabs>

<Info>
CI in the README invokes the published bin without a global install: `npx vwaffle plan --check`.
</Info>

## Published package

`files` is the npm tarball allowlist. Source, tests, `tsconfig.json`, and `bun.lock` are not published.

| Field | Value |
| --- | --- |
| `name` | `vwaffle` |
| `version` | `0.1.0` |
| `type` | `module` |
| `bin.vwaffle` | `./dist/index.js` |
| `files` | `dist`, `README.md`, `LICENSE` |
| `prepublishOnly` | `bun run typecheck && bun run test && bun run build` |

:::files
vwaffle@0.1.0 (npm tarball)
├── dist/index.js   # bin name: vwaffle; shebang #!/usr/bin/env node
├── README.md
└── LICENSE
:::

`prepublishOnly` rebuilds `dist/` immediately before publish. A git checkout does **not** contain that file: `.gitignore` lists `dist/`.

## The `dist/index.js` binary

`bun build src/index.ts --outdir dist --target node` emits a single Node entry that inlines `src/index.ts`, `src/api.ts`, `src/config.ts`, and `src/diff.ts`. A local build produces an executable `dist/index.js` (~12.5 KB) that starts with:

```js
#!/usr/bin/env node
```

`src/index.ts` hardcodes `VERSION = '0.1.0'` (same string as `package.json`). `--version` / `-v` prints that value to stdout. Default command when no subcommand is given is `help`.

```text
git checkout                 npm tarball / npx / bunx
─────────────                ────────────────────────
src/index.ts  ── bun build ──►  dist/index.js
  shebang + CLI                  Node ESM, executable
dist/ is gitignored              files[] ships dist only
```

<Warning>
`npm install -g .` or `npm link` from a clone fails until `bun run build` (or `prepublishOnly`) has created `dist/index.js`. Use `bun run src/index.ts` for a source-tree run without a build.
</Warning>

## Verify the install

<Steps>
<Step title="Print help">
Run `vwaffle`, `vwaffle help`, or `vwaffle --help` / `-h`. Expected first line:

```text
vwaffle 0.1.0 — config-as-code for Vercel WAF / Security / Bot Protection
```

Usage line: `vwaffle <command> [options]`.
</Step>
<Step title="Print version">
```sh
vwaffle --version
# or
vwaffle -v
```

Expected stdout: `0.1.0`.
</Step>
</Steps>

<RequestExample>
```sh
npx vwaffle --version
npx vwaffle help
```
</RequestExample>

<ResponseExample>
```text
0.1.0
```
</ResponseExample>

## Commands after install

| Command | Needs Vercel context | Behavior |
| --- | --- | --- |
| `help` (default) | no | Print usage |
| `--version` / `-v` | no | Print `0.1.0` |
| `init` | no | Write starter `firewall.config.json` |
| `pull` | yes | GET live firewall config |
| `plan` | yes | Diff live vs desired JSON |
| `apply --yes` | yes | PUT desired config |

Global flags on the published bin: `-c` / `--config`, `-o` / `--output`, `--check`, `--dry-run`, `--yes`, `--project`, `--team`, `-h` / `--help`, `-v` / `--version`.

## From a git checkout

Bun is the development toolchain, not a runtime requirement for the published package.

```sh
bun install
bun run build          # writes dist/index.js (Node target)
bun run src/index.ts help
```

| Script | Command |
| --- | --- |
| `build` | `bun build src/index.ts --outdir dist --target node` |
| `dev` | `bun run src/index.ts` |
| `typecheck` | `tsc --noEmit` |
| `test` | `bun test` |

`tsconfig.json` is `noEmit` with `moduleResolution: "bundler"` and `allowImportingTsExtensions`. Typecheck does not produce the bin; only `bun run build` (or `prepublishOnly`) does.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| `vwaffle: command not found` | Global bin not on `PATH`, or no install | Re-run `npm install -g vwaffle`, or use `npx` / `bunx` |
| `Cannot find module` / missing `dist/index.js` | Clone or `npm install .` without a build | `bun run build`, or install from the published package |
| npm `EBADENGINE` / engine warning | Node older than 18 | Install Node `>=18` |
| `vwaffle: unknown command …` | Typo or extra positional | `vwaffle help` |
| `vwaffle: unknown option …` | Flag not in the parser | Use documented flags only |
| `vwaffle: VERCEL_TOKEN is required.` | `pull` / `plan` / `apply` without a token | Export `VERCEL_TOKEN`; not an install failure |

Fatal CLI errors go to stderr as `vwaffle: <message>` and set `process.exitCode = 1`.

## Next

<CardGroup>
<Card title="Quickstart" href="/quickstart">
Set `VERCEL_TOKEN`, scaffold or pull `firewall.config.json`, then `plan` and `apply --yes`.
</Card>
<Card title="CLI reference" href="/cli-reference">
Commands, flags, and help text for the published `vwaffle` bin.
</Card>
<Card title="Environment variables" href="/environment-variables">
`VERCEL_TOKEN`, project/team IDs, and `${VAR_NAME}` interpolation after the CLI is installed.
</Card>
<Card title="Build and test" href="/build-and-test">
Bun typecheck, `bun test`, and the `src/index.ts` → `dist` bundle used to produce the binary.
</Card>
<Card title="Contributing" href="/contributing">
`prepublishOnly` gates, Node engine, Apache-2.0 metadata, and the files npm publishes.
</Card>
</CardGroup>
