@atrahasis/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # atra
2
+
3
+ **Atrahasis CLI** - atra
4
+
5
+ A fast, modern HTTP client CLI built with Rust. Supports HTTP/1.1, HTTP/2, and HTTP/3 (QUIC) with built-in load testing, flow runner, assertions, and detailed request tracing.
6
+
7
+ ## Installation
8
+
9
+ **npm**
10
+
11
+ ```bash
12
+ npm install -g @atrahasis/cli
13
+ ```
14
+
15
+ **Homebrew**
16
+
17
+ ```bash
18
+ brew install atrahasisdev/tap/atra
19
+ ```
20
+
21
+ **curl**
22
+
23
+ ```bash
24
+ curl -sSL https://cli.atrahasis.dev | sh
25
+ ```
26
+
27
+ **wget**
28
+
29
+ ```bash
30
+ wget -qO- https://cli.atrahasis.dev | sh
31
+ ```
32
+
33
+ **PowerShell (Windows)**
34
+
35
+ ```powershell
36
+ irm https://cli.atrahasis.dev | iex
37
+ ```
38
+
39
+ Verify your installation:
40
+
41
+ ```bash
42
+ atra --version
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # Simple GET request
49
+ atra GET https://api.example.com/users
50
+
51
+ # POST with JSON body
52
+ atra POST https://api.example.com/users name:John age:25
53
+
54
+ # POST with raw JSON
55
+ atra POST https://api.example.com/users \
56
+ -H "Content-Type: application/json" \
57
+ -d '{"name": "John", "age": 25}'
58
+
59
+ # Headers and auth
60
+ atra GET https://api.example.com/users -H "Accept: application/json" --bearer my-token
61
+
62
+ # Form data
63
+ atra POST https://api.example.com/upload -F "file=@photo.jpg" -F "caption=Hello"
64
+ ```
65
+
66
+ ## Request Tracing (`--trace`)
67
+
68
+ Get a full timing breakdown of every phase in the request lifecycle:
69
+
70
+ ```bash
71
+ atra GET https://api.example.com --trace
72
+ ```
73
+
74
+ ```
75
+ Response Time 652.27 ms
76
+
77
+ Prepare █ 6 µs
78
+ DNS Lookup █ 3.47 ms
79
+ TCP Handshake ██████ 160.91 ms
80
+ TLS Handshake ██████████████ 326.10 ms
81
+ Request Send █ 710 µs
82
+ Server Response ███████ 164.51 ms
83
+ Download 31 µs
84
+ Processing 1 µs
85
+ ```
86
+
87
+ Use `-t` as shorthand:
88
+
89
+ ```bash
90
+ atra GET https://api.example.com -t
91
+ ```
92
+
93
+ Combine with verbose mode to see full request/response details alongside timing:
94
+
95
+ ```bash
96
+ atra GET https://api.example.com -t -v
97
+ ```
98
+
99
+ ## HTTP/3 (QUIC)
100
+
101
+ atra has native HTTP/3 support via QUIC - no extra configuration needed:
102
+
103
+ ```bash
104
+ # Force HTTP/3
105
+ atra GET https://api.example.com --http3
106
+
107
+ # Force HTTP/2
108
+ atra GET https://api.example.com --http2
109
+
110
+ # Force HTTP/1.1
111
+ atra GET https://api.example.com --http1.1
112
+ ```
113
+
114
+ When no protocol is forced, atra automatically negotiates the best available protocol and pools connections for reuse.
115
+
116
+ ## Assertions
117
+
118
+ Validate responses directly from the command line. Exit code 1 on failure - perfect for CI/CD:
119
+
120
+ ```bash
121
+ # Status code
122
+ atra GET https://api.example.com --assert "status equals 200"
123
+
124
+ # Response time
125
+ atra GET https://api.example.com -a "response_time less_than 500"
126
+
127
+ # Body content
128
+ atra GET https://api.example.com -a "body contains success"
129
+
130
+ # JSON path
131
+ atra GET https://api.example.com -a "$.data.id exists"
132
+ atra GET https://api.example.com -a "$.users[0].name equals John"
133
+
134
+ # Headers
135
+ atra GET https://api.example.com -a "header Content-Type contains json"
136
+
137
+ # Multiple assertions
138
+ atra GET https://api.example.com \
139
+ -a "status equals 200" \
140
+ -a "response_time less_than 1000" \
141
+ -a "body contains users"
142
+ ```
143
+
144
+ **Assertion Targets**
145
+
146
+ | Target | Syntax | Description |
147
+ |--------|--------|-------------|
148
+ | `status` | `status operator value` | HTTP status code (e.g., 200, 404, 500) |
149
+ | `response_time` | `response_time operator ms` | Response time in milliseconds |
150
+ | `header` | `header name operator value` | Response header value (case-insensitive name) |
151
+ | `body` | `body operator value` | Full response body as string |
152
+ | `$.` | `$.path operator value` | JSON path - dot notation with array indexing (e.g., `$.users[0].name`) |
153
+
154
+ **Operators**
155
+
156
+ Each operator has short and long forms. Use whichever feels more natural.
157
+
158
+ | Short | Long | Description |
159
+ |-------|------|-------------|
160
+ | `eq` | `equals` | Exact match |
161
+ | `neq` | `not_equals` | Not equal |
162
+ | `gt` | `greater_than` | Numeric greater than |
163
+ | `lt` | `less_than` | Numeric less than |
164
+ | | `contains` | String contains |
165
+ | | `not_contains` | String does not contain |
166
+ | | `exists` | Value exists (not null) |
167
+ | | `not_exists` | Value is null or missing |
168
+ | | `is_empty` | Empty string, array, or object |
169
+ | | `is_not_empty` | Non-empty value |
170
+ | | `matches_regex` | Regex pattern match |
171
+ | | `is_type` | Check JSON type (string, number, boolean, array, object, null) |
172
+
173
+ **Short form examples:**
174
+
175
+ ```bash
176
+ atra GET https://api.example.com -a "status eq 200"
177
+ atra GET https://api.example.com -a "response_time lt 500"
178
+ atra GET https://api.example.com -a "$.data.count gt 0"
179
+ ```
180
+
181
+ ## Random Data Generation
182
+
183
+ Generate dynamic test data with 25+ built-in generators:
184
+
185
+ ```bash
186
+ # Random email and UUID
187
+ atra POST https://api.example.com/users \
188
+ '{"email": "{{random.email}}", "id": "{{random.uuid}}"}'
189
+
190
+ # Random string with length
191
+ atra POST https://api.example.com/data name:"{{random.string(20)}}"
192
+
193
+ # Random number in range
194
+ atra POST https://api.example.com/data score:"{{random.number(1,100)}}"
195
+
196
+ # Pick from a list
197
+ atra POST https://api.example.com/data color:"{{random.enum(red,green,blue)}}"
198
+
199
+ # Custom pattern
200
+ atra POST https://api.example.com/data code:"{{random.custom([A-Z]{3}-\d{4})}}"
201
+ ```
202
+
203
+ Available generators: `uuid`, `email`, `name`, `string`, `number`, `boolean`, `date`, `ip`, `slug`, `url`, `phone`, and more.
204
+
205
+ ## Flow Runner
206
+
207
+ Execute sequential API call chains defined in `.flow.json` files. Supports variable extraction, pre/post scripts, assertions, and retry logic.
208
+
209
+ ```bash
210
+ # Run all flows in a directory
211
+ atra run api-tests
212
+
213
+ # Run a specific flow
214
+ atra run api-tests -f user-registration
215
+
216
+ # Run with environment
217
+ atra run api-tests -f user-registration -e dev
218
+
219
+ # Sequential iterations (5 times)
220
+ atra run api-tests -f user-registration -i 5
221
+
222
+ # Parallel execution (3 workers)
223
+ atra run api-tests -f user-registration -p 3
224
+
225
+ # Stop on first failure
226
+ atra run api-tests -f user-registration -c
227
+ ```
228
+
229
+ If you are already inside the flow directory:
230
+
231
+ ```bash
232
+ atra run
233
+ atra run -f flow-name
234
+ ```
235
+
236
+ **Flow Runner Flags**
237
+
238
+ | Flag | Alias | Description |
239
+ |------|-------|-------------|
240
+ | `-f` | `--flow` | Flow names (comma-separated) |
241
+ | `-e` | `--env` | Environment name |
242
+ | `-i` | `--iterations` | Iteration count (default: 1) |
243
+ | `-p` | `--parallel` | Parallel worker count (default: 1) |
244
+ | `-c` | `--stop-on-failure` | Stop on first failure |
245
+
246
+ **Variable Types**
247
+
248
+ - `{{flow.varName}}` - Flow variables - carry data between steps
249
+ - `{{varName}}` - Environment variables
250
+ - `{{random.type}}` - Random value generated on each use
251
+
252
+ **Exit Codes:** `0` = all steps and assertions passed, `1` = failure
253
+
254
+ Features a live terminal dashboard with step-by-step progress, response times, assertion results, and anomaly detection.
255
+
256
+ ## Load Testing
257
+
258
+ Run load tests from `.spec.json` files with virtual users, stages, and thresholds.
259
+
260
+ ```bash
261
+ # Run all specs in a directory
262
+ atra run spec-folder
263
+
264
+ # Run specific specs
265
+ atra run spec-folder -s user-api,auth-api
266
+
267
+ # Run with environment
268
+ atra run spec-folder -s user-api -e staging
269
+
270
+ # Stress test
271
+ atra run spec-folder -s user-api -t stress
272
+
273
+ # Spike test
274
+ atra run spec-folder -s user-api -t spike
275
+
276
+ # Soak test
277
+ atra run spec-folder -s user-api -t soak
278
+ ```
279
+
280
+ **Test Types**
281
+
282
+ | Type | VUs | Ramp | Duration | Purpose |
283
+ |------|-----|------|----------|---------|
284
+ | `load` (default) | 50 | 30s | 60s | Gradual ramp up, sustained load, gradual ramp down |
285
+ | `stress` | 200 | 10s | 60s | Aggressive increase to find breaking points |
286
+ | `spike` | 300 | 2s | 30s | Sudden spike to high load |
287
+ | `soak` | 30 | 30s | 300s | Long duration with low, steady load |
288
+ | `custom` | Custom | Custom | Custom | User-defined stages |
289
+
290
+ **Load Test Flags**
291
+
292
+ | Flag | Alias | Description |
293
+ |------|-------|-------------|
294
+ | `-s` | `--spec` | Spec names (comma-separated) |
295
+ | `-t` | `--type` | Test type |
296
+ | `-e` | `--env` | Environment name |
297
+
298
+ Includes a real-time terminal dashboard with live charts, response time percentiles, error tracking, and threshold monitoring.
299
+
300
+ **Report Formats:** HTML, PDF, OpenTelemetry JSON
301
+
302
+ ## CI/CD
303
+
304
+ atra works in any CI/CD pipeline. Assertions return exit code 1 on failure.
305
+
306
+ **GitHub Actions**
307
+
308
+ ```yaml
309
+ - name: API Health Check
310
+ run: |
311
+ curl -sSL https://cli.atrahasis.dev | sh
312
+ atra GET https://api.example.com \
313
+ -a "status eq 200" \
314
+ -a "response_time lt 2000"
315
+ ```
316
+
317
+ **With npm/npx (no install needed)**
318
+
319
+ ```yaml
320
+ - name: API Health Check
321
+ run: npx --yes @atrahasis/cli GET https://api.example.com -a "status eq 200"
322
+ ```
323
+
324
+ **GitHub Actions (Windows)**
325
+
326
+ ```yaml
327
+ - name: API Health Check
328
+ shell: pwsh
329
+ run: |
330
+ irm https://cli.atrahasis.dev | iex
331
+ atra GET https://api.example.com -a "status eq 200"
332
+ ```
333
+
334
+ **GitLab CI**
335
+
336
+ ```yaml
337
+ api-test:
338
+ script:
339
+ - curl -sSL https://cli.atrahasis.dev | sh
340
+ - atra GET https://api.example.com -a "status eq 200"
341
+ ```
342
+
343
+ **Run flow tests in CI**
344
+
345
+ ```yaml
346
+ - name: Run API Flow Tests
347
+ run: |
348
+ curl -sSL https://cli.atrahasis.dev | sh
349
+ atra run ./tests -f smoke-test -e ci
350
+ ```
351
+
352
+ ## Additional Features
353
+
354
+ | Feature | Flag |
355
+ |---------|------|
356
+ | Follow redirects | `-L` |
357
+ | Timeout | `-m 30` |
358
+ | Retry on failure | `--retry 3` |
359
+ | Skip TLS verification | `-k` |
360
+ | Basic auth | `-u user:pass` |
361
+ | Bearer token | `--bearer token` |
362
+ | OAuth 2.0 | `--oauth2 flow:url:id:secret` |
363
+ | Download file | `-D output.zip` |
364
+ | Cookie support | `-b "key=value"` |
365
+ | Named sessions | `-N my-session` |
366
+ | Verbose output | `-v` |
367
+ | JSON output | `--json` |
368
+ | Dry run | `-r` |
369
+ | Certificate info | `-C` |
370
+ | Silent mode | `-s` |
371
+
372
+ ## Platform Support
373
+
374
+ | Platform | Architecture | Status |
375
+ |----------|-------------|--------|
376
+ | macOS | Apple Silicon (arm64) | Available |
377
+ | macOS | Intel (x86_64) | Available |
378
+ | Linux | arm64 | Available |
379
+ | Linux | x86_64 | Available |
380
+ | Windows | x86_64 | Available |
381
+
382
+ ## Links
383
+
384
+ - [Atrahasis](https://atrahasis.dev)
385
+ - [atra Documentation](https://atrahasis.dev/cli)
386
+
387
+ ## License
388
+
389
+ Proprietary - Atrahasis
package/bin/atra.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execFileSync } = require("child_process");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+
7
+ const ext = process.platform === "win32" ? ".exe" : "";
8
+ const binPath = path.join(__dirname, "atra-native" + ext);
9
+
10
+ if (!fs.existsSync(binPath)) {
11
+ console.error("atra binary not found. Try reinstalling: npm install -g @atrahasis/cli");
12
+ process.exit(1);
13
+ }
14
+
15
+ try {
16
+ execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
17
+ } catch (err) {
18
+ process.exit(err.status || 1);
19
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@atrahasis/cli",
3
+ "version": "1.0.0",
4
+ "description": "A fast, modern HTTP client CLI with load testing and flow runner",
5
+ "bin": {
6
+ "atra": "bin/atra.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/install.js"
10
+ },
11
+ "os": ["darwin", "linux", "win32"],
12
+ "keywords": ["http", "http-client", "rest-client", "cli", "api", "api-testing", "load-testing", "stress-test", "flow-runner", "http3", "quic", "assertions", "workflow", "runner"],
13
+ "author": "Atrahasis",
14
+ "license": "Proprietary",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/atrahasisdev/cli-releases.git"
18
+ },
19
+ "homepage": "https://atrahasis.dev/cli"
20
+ }
@@ -0,0 +1,99 @@
1
+ const { execFileSync } = require("child_process");
2
+ const os = require("os");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const https = require("https");
6
+
7
+ const REPO = "atrahasisdev/cli-releases";
8
+ const BIN_DIR = path.join(__dirname, "..", "bin");
9
+ const IS_WIN = os.platform() === "win32";
10
+ const BIN_NAME = IS_WIN ? "atra-native.exe" : "atra-native";
11
+ const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
12
+
13
+ function getPlatform() {
14
+ const platform = os.platform();
15
+ const arch = os.arch();
16
+
17
+ const platformMap = {
18
+ darwin: "apple-darwin",
19
+ linux: "unknown-linux-gnu",
20
+ win32: "pc-windows-msvc",
21
+ };
22
+
23
+ const archMap = {
24
+ x64: "x86_64",
25
+ arm64: "aarch64",
26
+ };
27
+
28
+ const osTarget = platformMap[platform];
29
+ const archTarget = archMap[arch];
30
+
31
+ if (!osTarget || !archTarget) {
32
+ console.error(`Unsupported platform: ${platform}-${arch}`);
33
+ process.exit(1);
34
+ }
35
+
36
+ return { osTarget, archTarget, isWindows: IS_WIN };
37
+ }
38
+
39
+ function httpsGet(url) {
40
+ return new Promise((resolve, reject) => {
41
+ https.get(url, { headers: { "User-Agent": "atrahasis-npm" } }, (res) => {
42
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
43
+ return httpsGet(res.headers.location).then(resolve).catch(reject);
44
+ }
45
+ const chunks = [];
46
+ res.on("data", (chunk) => chunks.push(chunk));
47
+ res.on("end", () => resolve({ statusCode: res.statusCode, body: Buffer.concat(chunks) }));
48
+ res.on("error", reject);
49
+ }).on("error", reject);
50
+ });
51
+ }
52
+
53
+ async function getLatestVersion() {
54
+ const res = await httpsGet(`https://api.github.com/repos/${REPO}/releases/latest`);
55
+ const data = JSON.parse(res.body.toString());
56
+ return data.tag_name;
57
+ }
58
+
59
+ async function downloadBinary(version, archTarget, osTarget, isWindows) {
60
+ const ext = isWindows ? "zip" : "tar.gz";
61
+ const filename = `atra-${archTarget}-${osTarget}.${ext}`;
62
+ const url = `https://github.com/${REPO}/releases/download/${version}/${filename}`;
63
+
64
+ console.log(`Downloading atra ${version} for ${archTarget}-${osTarget}...`);
65
+
66
+ const res = await httpsGet(url);
67
+ if (res.statusCode !== 200) {
68
+ console.error(`Download failed with status ${res.statusCode}`);
69
+ process.exit(1);
70
+ }
71
+
72
+ const tmpFile = path.join(os.tmpdir(), filename);
73
+ fs.writeFileSync(tmpFile, res.body);
74
+
75
+ fs.mkdirSync(BIN_DIR, { recursive: true });
76
+
77
+ if (isWindows) {
78
+ execFileSync("powershell", ["-Command", `Expand-Archive -Path '${tmpFile}' -DestinationPath '${BIN_DIR}' -Force`], { stdio: "pipe" });
79
+ fs.renameSync(path.join(BIN_DIR, "atra.exe"), BIN_PATH);
80
+ } else {
81
+ execFileSync("tar", ["-xzf", tmpFile, "-C", BIN_DIR], { stdio: "pipe" });
82
+ fs.renameSync(path.join(BIN_DIR, "atra"), BIN_PATH);
83
+ fs.chmodSync(BIN_PATH, 0o755);
84
+ }
85
+
86
+ fs.unlinkSync(tmpFile);
87
+ console.log(`Successfully installed atra ${version}!`);
88
+ }
89
+
90
+ async function main() {
91
+ const { osTarget, archTarget, isWindows } = getPlatform();
92
+ const version = await getLatestVersion();
93
+ await downloadBinary(version, archTarget, osTarget, isWindows);
94
+ }
95
+
96
+ main().catch((err) => {
97
+ console.error("Installation failed:", err.message);
98
+ process.exit(1);
99
+ });