{"_id":"@connorlittleton/curly","_rev":"2-26ab696238f669446d269e6f063c1a9c","name":"@connorlittleton/curly","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@connorlittleton/curly","version":"0.0.1","keywords":["cli","curly"],"author":{"name":"Connor Littleton"},"license":"MIT","_id":"@connorlittleton/curly@0.0.1","maintainers":[{"name":"connorlittleton","email":"littletonconnor@gmail.com"}],"homepage":"https://github.com/Littletonconnor/curly#readme","bugs":{"url":"https://github.com/Littletonconnor/curly/issues"},"bin":{"curly":"bin/curly.js"},"dist":{"shasum":"d730145351882007aeb44c08c428337165a54cc4","tarball":"https://registry.npmjs.org/@connorlittleton/curly/-/curly-0.0.1.tgz","fileCount":5,"integrity":"sha512-94wDz+MjGqrBNtKaLJM5u/L09toe64v4lqwA/Vj2TOfaZWVMhkLo7IAIxiNBMqoqdgbWVfzPZuzml3Fh9TXSBg==","signatures":[{"sig":"MEYCIQDEanhsbOJ7JQqEB1pjbZmJvm0Zs60GDTDRXEQZ9HLkuQIhAMjafBh8ZWk60NnVlh3NG96AxFvhVIVB0RrsNABUlO/C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":317108},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"e69fc61e0d8370be9173aeacc7ba80678511aceb","private":false,"scripts":{"dev":"npm run build && ./bin/curly.js","build":"tsup --config ./tsup.config.ts","types":"tsc --noEmit","format":"prettier --write 'src/**/*.ts'","format:check":"prettier --check 'src/**/*.ts'"},"_npmUser":{"name":"connorlittleton","email":"littletonconnor@gmail.com"},"repository":{"url":"git+https://github.com/Littletonconnor/curly.git","type":"git"},"_npmVersion":"11.6.2","description":"A CLI tool for making curl easier to work with.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"ink":"^6.6.0","react":"^19.2.3","undici":"^7.18.2","asciichart":"^1.5.25"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","prettier":"^3.8.0","typescript":"^5.7.3","@types/node":"^22.10.5","@types/react":"^19.2.8","@types/asciichart":"^1.5.8"},"_npmOperationalInternal":{"tmp":"tmp/curly_0.0.1_1769381976309_0.7273715656808581","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@connorlittleton/curly","version":"0.0.2","private":false,"description":"A CLI tool for making curl easier to work with.","keywords":["cli","curly"],"repository":{"type":"git","url":"git+https://github.com/Littletonconnor/curly.git"},"license":"MIT","author":{"name":"Connor Littleton"},"type":"module","main":"dist/index.js","bin":{"curly":"bin/curly.js"},"scripts":{"build":"tsup --config ./tsup.config.ts","dev":"npm run build && ./bin/curly.js","format":"prettier --write 'src/**/*.ts'","format:check":"prettier --check 'src/**/*.ts'","types":"tsc --noEmit"},"dependencies":{"asciichart":"^1.5.25","ink":"^6.6.0","react":"^19.2.3","undici":"^7.18.2"},"devDependencies":{"@types/asciichart":"^1.5.8","@types/node":"^22.10.5","@types/react":"^19.2.8","prettier":"^3.8.0","tsup":"^8.3.5","typescript":"^5.7.3"},"engines":{"node":">=20"},"gitHead":"86f3cacdc9d058ac96f5d44473b6cd2093d82638","bugs":{"url":"https://github.com/Littletonconnor/curly/issues"},"homepage":"https://github.com/Littletonconnor/curly#readme","_id":"@connorlittleton/curly@0.0.2","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-YJXC707tQpPYn7iigWFN2bNH/7su1zARo3HH/ZIK6AyafqO7qzbaDyymdNO9RremqyrDDG+loa/s0NY47/cKMw==","shasum":"ae9647d718496ccb1d742cc117783dbb5409aeff","tarball":"https://registry.npmjs.org/@connorlittleton/curly/-/curly-0.0.2.tgz","fileCount":5,"unpackedSize":323298,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHUE72O8J6NSIpdeFaVbpxtFqiFzi0lqlnrdnL7/M5VPAiA9qyFWN/uIgKoJGFfRGfsav+derLu9jtWO6phN825wiw=="}]},"_npmUser":{"name":"connorlittleton","email":"littletonconnor@gmail.com"},"directories":{},"maintainers":[{"name":"connorlittleton","email":"littletonconnor@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/curly_0.0.2_1773512266203_0.004478525463211591"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-25T22:59:36.227Z","modified":"2026-03-14T18:17:46.455Z","0.0.1":"2026-01-25T22:59:36.478Z","0.0.2":"2026-03-14T18:17:46.340Z"},"bugs":{"url":"https://github.com/Littletonconnor/curly/issues"},"author":{"name":"Connor Littleton"},"license":"MIT","homepage":"https://github.com/Littletonconnor/curly#readme","keywords":["cli","curly"],"repository":{"type":"git","url":"git+https://github.com/Littletonconnor/curly.git"},"description":"A CLI tool for making curl easier to work with.","maintainers":[{"name":"connorlittleton","email":"littletonconnor@gmail.com"}],"readme":"# Curly\n\n![Curly Banner](./banner.svg)\n\nA modern, developer-friendly HTTP client for the command line. Curly wraps Node.js `fetch` with curl-like syntax, adding built-in load testing, configuration profiles, and intelligent defaults.\n\n## Table of Contents\n\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Requests](#basic-requests)\n  - [Headers & Authentication](#headers--authentication)\n  - [Request Body](#request-body)\n  - [Query Parameters](#query-parameters)\n  - [Cookies](#cookies)\n  - [Output Options](#output-options)\n  - [Timeouts & Retries](#timeouts--retries)\n  - [Redirects](#redirects)\n  - [Proxy Support](#proxy-support)\n- [Load Testing](#load-testing)\n- [Configuration](#configuration)\n  - [Profiles](#profiles)\n  - [Aliases](#aliases)\n  - [Environment Variables](#environment-variables)\n- [Shell Completions](#shell-completions)\n- [Command Reference](#command-reference)\n- [Requirements](#requirements)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- **Familiar Syntax** - Curl-compatible flags (`-X`, `-H`, `-d`, `-I`) for easy migration\n- **Smart Defaults** - Auto-sets `Content-Type: application/json` for POST requests with data\n- **Response Parsing** - Automatically detects and pretty-prints JSON responses\n- **Load Testing** - Built-in performance testing with histograms and percentile statistics\n- **Configuration Profiles** - Define environments (dev/staging/prod) with base URLs and headers\n- **Request Aliases** - Save and replay complex requests with a single command\n- **Environment Interpolation** - Inject `{{ENV_VARS}}` into URLs, headers, and bodies\n- **Cookie Management** - Full support for cookie files and cookie jars\n- **File Uploads** - Multipart form data with automatic MIME type detection\n- **Shell Completions** - Tab completion for bash and zsh\n\n## Quick Start\n\n```sh\n# Simple GET request\ncurly https://api.example.com/users/1\n\n# POST with JSON data\ncurly -X POST -d name=John -d email=john@example.com https://api.example.com/users\n\n# Load test with 1000 requests at 50 concurrency\ncurly -n 1000 -c 50 https://api.example.com/health\n```\n\n## Installation\n\n### npm (Recommended)\n\n```sh\nnpm install -g @cwl/curly\n```\n\n### From Source\n\n```sh\ngit clone https://github.com/Littletonconnor/curly.git\ncd curly\nnpm install\nnpm run build\nnpm link\n```\n\nVerify installation:\n\n```sh\ncurly --help\n```\n\n## Usage\n\n```\ncurly [OPTIONS] <url>\n```\n\n### Basic Requests\n\n```sh\n# GET request (default)\ncurly https://api.example.com/posts/1\n\n# Specify HTTP method\ncurly -X POST https://api.example.com/posts\ncurly -X PUT https://api.example.com/posts/1\ncurly -X PATCH https://api.example.com/posts/1\ncurly -X DELETE https://api.example.com/posts/1\n\n# HEAD request (headers only)\ncurly -I https://api.example.com/posts/1\n```\n\n### Headers & Authentication\n\n```sh\n# Custom headers\ncurly -H \"Accept: application/json\" -H \"X-API-Key: secret\" https://api.example.com\n\n# Basic authentication\ncurly -u username:password https://api.example.com/protected\n\n# Bearer token\ncurly -H \"Authorization: Bearer {{TOKEN}}\" https://api.example.com/secure\n```\n\n### Request Body\n\n**Key-value pairs** (automatically converted to JSON):\n\n```sh\ncurly -X POST -d title=\"Hello\" -d body=\"World\" https://api.example.com/posts\n# Sends: {\"title\": \"Hello\", \"body\": \"World\"}\n```\n\n**Raw JSON data**:\n\n```sh\ncurly -X POST --data-raw '{\"title\": \"Hello\", \"body\": \"World\"}' https://api.example.com/posts\n```\n\n**From file**:\n\n```sh\ncurly -X POST -d @payload.json https://api.example.com/posts\n```\n\n**Multipart form data** (file uploads):\n\n```sh\ncurly -F \"file=@document.pdf\" -F \"description=My file\" https://api.example.com/upload\n```\n\n### Query Parameters\n\n```sh\n# Using flags\ncurly -q page=1 -q limit=10 https://api.example.com/posts\n\n# In URL (also works)\ncurly \"https://api.example.com/posts?page=1&limit=10\"\n```\n\n### Cookies\n\n```sh\n# Send cookies\ncurly -b \"session=abc123\" -b \"user=john\" https://api.example.com\n\n# Send cookies from file\ncurly -b ./cookies.json https://api.example.com\n\n# Save received cookies\ncurly --cookie-jar ./cookies.json https://api.example.com/login\n```\n\n### Output Options\n\n```sh\n# Include response headers\ncurly -i https://api.example.com/posts/1\n\n# Save response to file\ncurly -o response.json https://api.example.com/posts/1\n\n# Quiet mode (suppress status line)\ncurly --quiet https://api.example.com/posts/1 | jq .title\n\n# Structured JSON output\ncurly --json https://api.example.com/posts/1\n\n# Extract specific values\ncurly -w http_code https://api.example.com/health\n# Output: 200\n\n# Verbose mode\ncurly -v https://api.example.com/posts/1\n\n# Dry run (preview request without sending)\ncurly --dry-run -X POST -d name=test https://api.example.com\n```\n\n### Timeouts & Retries\n\n```sh\n# Set timeout (milliseconds)\ncurly -t 5000 https://api.example.com/slow-endpoint\n\n# Retry with exponential backoff\ncurly --retry 3 https://api.example.com/flaky-endpoint\n\n# Custom retry delay\ncurly --retry 3 --retry-delay 500 https://api.example.com/flaky-endpoint\n\n# Exit with code 22 on HTTP errors\ncurly -f https://api.example.com/health || echo \"Health check failed\"\n```\n\n### Redirects\n\n```sh\n# Follow redirects\ncurly -L https://example.com/redirect\n\n# Limit redirect count\ncurly -L --max-redirects 5 https://example.com/redirect\n```\n\n### Proxy Support\n\n```sh\ncurly --proxy http://localhost:8080 https://api.example.com\ncurly -x http://proxy.company.com:3128 https://api.example.com\n```\n\n## Load Testing\n\nLoad testing mode activates automatically when `-n` (requests) or `-c` (concurrency) flags are present.\n\n```sh\n# Basic load test: 100 requests with 10 concurrent connections\ncurly -n 100 -c 10 https://api.example.com/posts/1\n```\n\n**Sample output**:\n\n```\nSummary:\n  Total:         2.5208 secs\n  Slowest:       0.3903 secs\n  Fastest:       0.0964 secs\n  Average:       0.1631 secs\n  Requests/sec:  475.25\n\nResponse time histogram:\n  0.096 [605]   |■■■■■■■■■■■■■■\n  0.126 [1741]  |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n  0.155 [1278]  |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n\nLatency distribution:\n  50% in 0.1647 secs\n  90% in 0.2010 secs\n  99% in 0.3278 secs\n\nStatus code distribution:\n  [200] 5000 responses\n```\n\n### Interactive TUI Dashboard\n\n```sh\ncurly -n 1000 -c 50 --tui https://api.example.com/posts\n```\n\nThe TUI provides real-time statistics, live histograms, and controls to pause/resume or adjust concurrency during the test.\n\n### Export Results\n\n```sh\n# Export to JSON\ncurly -n 100 -c 10 --export json https://api.example.com/posts\n\n# Export to CSV file\ncurly -n 100 -c 10 --export csv -o results.csv https://api.example.com/posts\n```\n\n## Configuration\n\n### Interactive Setup\n\nRun the configuration wizard to create profiles:\n\n```sh\ncurly --init\n```\n\nThis creates `~/.config/curly/config.json` with your settings.\n\n### Profiles\n\nDefine named profiles with base URLs, headers, and default settings:\n\n```json\n{\n  \"default\": \"dev\",\n  \"profiles\": {\n    \"dev\": {\n      \"baseUrl\": \"http://localhost:3000\",\n      \"timeout\": 5000,\n      \"headers\": [\"X-Debug: true\"]\n    },\n    \"prod\": {\n      \"baseUrl\": \"https://api.example.com\",\n      \"timeout\": 10000,\n      \"headers\": [\"Authorization: Bearer {{API_KEY}}\"],\n      \"retry\": 3\n    }\n  }\n}\n```\n\nUse profiles:\n\n```sh\n# Uses default profile\ncurly /users\n\n# Specify profile\ncurly --profile prod /users\n\n# CLI flags override profile settings\ncurly --profile prod --timeout 30000 /users\n```\n\n**Profile options**:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `baseUrl` | string | Prepended to paths starting with `/` |\n| `timeout` | number | Request timeout in milliseconds |\n| `headers` | string[] | Headers in `\"Name: value\"` format |\n| `retry` | number | Number of retry attempts |\n| `retryDelay` | number | Initial retry delay in milliseconds |\n\n### Aliases\n\nSave complex requests for reuse:\n\n```sh\n# Save a request\ncurly --save \"create-user\" -X POST \\\n  -H \"Authorization: Bearer {{TOKEN}}\" \\\n  -d name=John -d email=john@example.com \\\n  https://api.example.com/users\n\n# Execute saved alias\ncurly --use \"create-user\"\n\n# List all aliases\ncurly --aliases\n\n# Delete an alias\ncurly --delete-alias \"create-user\"\n```\n\nAliases support environment variable interpolation - variables are resolved when the alias is executed.\n\n### Environment Variables\n\nUse `{{VAR}}` syntax to inject environment variables:\n\n```sh\nexport API_KEY=\"sk-12345\"\nexport BASE_URL=\"https://api.example.com\"\n\ncurly -H \"Authorization: Bearer {{API_KEY}}\" \"{{BASE_URL}}/users\"\n```\n\nWorks in URLs, headers, data, query parameters, cookies, and authentication credentials.\n\n## Shell Completions\n\nInstall tab completions:\n\n```sh\ncurly --completions install\n```\n\nThen restart your shell or source your config:\n\n```sh\nsource ~/.bashrc   # bash\nsource ~/.zshrc    # zsh\n```\n\n## Command Reference\n\n| Option | Short | Description |\n|--------|-------|-------------|\n| `--help` | `-h` | Display help information |\n| `--method` | `-X` | HTTP method (GET, POST, PUT, DELETE, etc.) |\n| `--headers` | `-H` | Add custom headers (repeatable) |\n| `--data` | `-d` | Key=value pairs or @filename (repeatable) |\n| `--data-raw` | | Send raw data |\n| `--form` | `-F` | Multipart form data (repeatable) |\n| `--query` | `-q` | Query parameters (repeatable) |\n| `--cookie` | `-b` | Cookies (key=value or file path, repeatable) |\n| `--cookie-jar` | | Save cookies to file |\n| `--output` | `-o` | Write response to file |\n| `--include` | `-i` | Include response headers |\n| `--head` | `-I` | Fetch headers only |\n| `--verbose` | `-v` | Show detailed request/response |\n| `--dry-run` | | Preview request without sending |\n| `--quiet` | | Suppress status line |\n| `--json` | `-j` | Output as structured JSON |\n| `--write-out` | `-w` | Extract response info (http_code, time_total, size_download) |\n| `--timeout` | `-t` | Request timeout in milliseconds |\n| `--follow` | `-L` | Follow HTTP redirects |\n| `--max-redirects` | | Maximum redirects (default: 20) |\n| `--fail` | `-f` | Exit with code 22 on HTTP errors |\n| `--retry` | | Retry attempts with exponential backoff |\n| `--retry-delay` | | Initial retry delay in milliseconds |\n| `--user` | `-u` | Basic authentication (user:password) |\n| `--proxy` | `-x` | HTTP/HTTPS proxy URL |\n| `--requests` | `-n` | Number of requests (load testing) |\n| `--concurrency` | `-c` | Concurrency level (load testing) |\n| `--tui` | `-T` | Interactive TUI dashboard |\n| `--export` | `-e` | Export results (json, csv) |\n| `--profile` | `-p` | Use named profile |\n| `--init` | | Interactive configuration wizard |\n| `--save` | | Save request as alias |\n| `--use` | | Execute saved alias |\n| `--aliases` | | List saved aliases |\n| `--delete-alias` | | Delete an alias |\n| `--completions` | | Shell completion (bash, zsh, install) |\n| `--history` | | View command history |\n\n## Requirements\n\n- Node.js >= 20\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes\n4. Run tests: `./examples/run-all-examples.sh`\n5. Run checks: `npm run types && npm run format:check`\n6. Commit your changes\n7. Push to your branch\n8. Open a Pull Request\n\n## License\n\nMIT\n","readmeFilename":"README.md"}