@anonymilyhq/cli 1.0.0 → 1.0.1

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,47 @@
1
+ # @anonymilyhq/cli
2
+
3
+ The official CLI for [Anonymily](https://anonymily.com), a simple and powerful webhook relayer.
4
+
5
+ With the Anonymily CLI, you can forward webhooks directly from Anonymily to your local machine, allowing you to easily test, inspect, and debug incoming webhooks in real-time.
6
+
7
+ ## Installation
8
+
9
+ You can install the CLI globally using npm:
10
+
11
+ ```bash
12
+ npm install -g @anonymilyhq/cli
13
+ ```
14
+
15
+ Alternatively, you can run it directly using `npx`:
16
+
17
+ ```bash
18
+ npx @anonymilyhq/cli listen 8080
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Start listening for incoming webhooks and forward them to a specific port on your localhost:
24
+
25
+ ```bash
26
+ anonymily listen <port>
27
+ ```
28
+
29
+ ### Example
30
+
31
+ To forward webhooks to your local development server running on port `3000`:
32
+
33
+ ```bash
34
+ anonymily listen 3000
35
+ ```
36
+
37
+ 1. The CLI will generate a unique webhook connection URL and a Hook ID.
38
+ 2. Send your webhooks to the provided URL.
39
+ 3. The CLI will receive the requests natively and forward them precisely to `http://localhost:3000`, preserving exactly the same method, body, queries, and headers.
40
+
41
+ ## Issues
42
+
43
+ If you encounter a bug, please create an issue in the main repository or contact our support.
44
+
45
+ ## License
46
+
47
+ MIT
package/bin/cli.js CHANGED
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { EventSource as EventSourceConstructor } from 'eventsource';
4
-
5
3
  import { program } from 'commander';
6
- import pc from 'picocolors';
4
+ import { generateHookId } from '../lib/utils.js';
5
+ import { startForwarding } from '../lib/forwarder.js';
7
6
 
8
7
  // Point this to your live production backend URL
9
8
  const API_URL = process.env.ANONYMILY_API_URL || 'https://api.anonymily.com';
@@ -18,56 +17,8 @@ program
18
17
  .description('Listen for incoming webhooks and forward them to a local port')
19
18
  .argument('<port>', 'Local port to forward to (e.g., 8080)')
20
19
  .action((port) => {
21
- startListening(port);
20
+ const hookId = generateHookId();
21
+ startForwarding(API_URL, hookId, parseInt(port, 10));
22
22
  });
23
23
 
24
- program.parse();
25
-
26
- async function startListening(port) {
27
- // 1. Generate a random Hook ID
28
- const hookId = Math.random().toString(36).substring(2, 10);
29
- const webhookUrl = `${API_URL}/h/${hookId}`;
30
- const localUrl = `http://localhost:${port}`;
31
-
32
- console.log(pc.green(pc.bold(`\nšŸš€ Anonymily CLI is running!`)));
33
- console.log(`\nForwarding: ${pc.cyan(webhookUrl)} āž” ${pc.cyan(localUrl)}`);
34
- console.log(pc.dim(`Waiting for requests to arrive...\n`));
35
-
36
- // 2. Connect to the Server-Sent Events stream using the safe constructor
37
- const es = new EventSourceConstructor(`${API_URL}/stream/${hookId}`);
38
-
39
- es.onmessage = async (event) => {
40
- const reqData = JSON.parse(event.data);
41
- const { method, headers, query, body } = reqData;
42
-
43
- // 3. Clean up headers before forwarding
44
- const forwardHeaders = { ...headers };
45
- delete forwardHeaders.host;
46
- delete forwardHeaders.connection;
47
-
48
- // Reconstruct query parameters
49
- const queryString = new URLSearchParams(query).toString();
50
- const fullLocalUrl = queryString ? `${localUrl}?${queryString}` : localUrl;
51
-
52
- console.log(pc.yellow(`[${new Date().toLocaleTimeString()}] ⚔ Incoming ${method} request...`));
53
-
54
- try {
55
- // 4. Forward the exact payload to localhost
56
- const response = await fetch(fullLocalUrl, {
57
- method: method,
58
- headers: forwardHeaders,
59
- body: ['GET', 'HEAD'].includes(method) ? undefined : JSON.stringify(body)
60
- });
61
-
62
- const statusColor = response.ok ? pc.green : pc.red;
63
- console.log(` └─ Forwarded to localhost | Status: ${statusColor(response.status)}\n`);
64
- } catch (err) {
65
- console.log(pc.red(` └─ Error forwarding: ${err.message}`));
66
- console.log(pc.dim(` Make sure your local server is actually running on port ${port}\n`));
67
- }
68
- };
69
-
70
- es.onerror = () => {
71
- console.error(pc.red(`\nConnection error. Attempting to reconnect...`));
72
- };
73
- }
24
+ program.parse();
@@ -0,0 +1,48 @@
1
+ import { EventSource as EventSourceConstructor } from 'eventsource';
2
+ import pc from 'picocolors';
3
+ import { logger } from './logger.js';
4
+
5
+ export function startForwarding(apiUrl, hookId, port) {
6
+ const webhookUrl = `${apiUrl}/h/${hookId}`;
7
+ const localUrl = `http://localhost:${port}`;
8
+
9
+ logger.success(pc.bold(`\nšŸš€ Anonymily CLI is running!`));
10
+ logger.raw(`\nForwarding: ${pc.cyan(webhookUrl)} āž” ${pc.cyan(localUrl)}`);
11
+ logger.dim(`Waiting for requests to arrive...\n`);
12
+
13
+ const es = new EventSourceConstructor(`${apiUrl}/stream/${hookId}`);
14
+
15
+ es.onmessage = async (event) => {
16
+ try {
17
+ const reqData = JSON.parse(event.data);
18
+ const { method, headers, query, body } = reqData;
19
+
20
+ const forwardHeaders = { ...headers };
21
+ delete forwardHeaders.host;
22
+ delete forwardHeaders.connection;
23
+
24
+ const queryString = new URLSearchParams(query || {}).toString();
25
+ const fullLocalUrl = queryString ? `${localUrl}?${queryString}` : localUrl;
26
+
27
+ logger.warn(`[${new Date().toLocaleTimeString()}] ⚔ Incoming ${method} request...`);
28
+
29
+ const response = await fetch(fullLocalUrl, {
30
+ method: method,
31
+ headers: forwardHeaders,
32
+ body: ['GET', 'HEAD'].includes(method) ? undefined : JSON.stringify(body)
33
+ });
34
+
35
+ const statusColor = response.ok ? pc.green : pc.red;
36
+ logger.raw(` └─ Forwarded to localhost | Status: ${statusColor(response.status)}\n`);
37
+ } catch (err) {
38
+ logger.error(` └─ Error forwarding: ${err.message}`);
39
+ logger.dim(` Make sure your local server is actually running on port ${port}\n`);
40
+ }
41
+ };
42
+
43
+ es.onerror = () => {
44
+ logger.error(`\nConnection error. Attempting to reconnect...`);
45
+ };
46
+
47
+ return es;
48
+ }
package/lib/logger.js ADDED
@@ -0,0 +1,11 @@
1
+ import pc from 'picocolors';
2
+
3
+ export const logger = {
4
+ info: (msg) => console.log(pc.cyan(msg)),
5
+ success: (msg) => console.log(pc.green(msg)),
6
+ warn: (msg) => console.log(pc.yellow(msg)),
7
+ error: (msg) => console.log(pc.red(msg)),
8
+ dim: (msg) => console.log(pc.dim(msg)),
9
+ bold: (msg) => console.log(pc.bold(msg)),
10
+ raw: (msg) => console.log(msg),
11
+ };
package/lib/utils.js ADDED
@@ -0,0 +1,3 @@
1
+ export function generateHookId() {
2
+ return Math.random().toString(36).substring(2, 10);
3
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@anonymilyhq/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI for Anonymily platform",
5
5
  "type": "module",
6
6
  "bin": {
7
- "anonymily": "./bin/cli.js"
7
+ "anonymily": "bin/cli.js"
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node ./bin/cli.js"
@@ -16,9 +16,11 @@
16
16
  "devtools",
17
17
  "api-client"
18
18
  ],
19
+ "author": "Anonymily",
20
+ "license": "MIT",
19
21
  "files": [
20
22
  "bin",
21
- "index.js",
23
+ "lib",
22
24
  "README.md"
23
25
  ],
24
26
  "dependencies": {
@@ -26,4 +28,4 @@
26
28
  "eventsource": "^4.1.0",
27
29
  "picocolors": "^1.1.1"
28
30
  }
29
- }
31
+ }