@anonymilyhq/cli 1.0.4 → 1.1.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 +48 -9
- package/bin/cli.js +34 -1
- package/lib/feedback.js +36 -0
- package/lib/forwarder.js +52 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
The Anonymily CLI connects to your live webhook endpoint on `api.anonymily.com` via a Server-Sent Events (SSE) stream and forwards every incoming request — with the exact same method, headers, query params, and body — to a port on your local machine.
|
|
18
18
|
|
|
19
|
-
No tunnels
|
|
19
|
+
**No tunnels. No signup. No account required.** Just one command.
|
|
20
20
|
|
|
21
|
-
> **
|
|
21
|
+
> **Want more?** Upgrade to Pro (₹750/month) to claim persistent hooks and unlock 500 requests + 30-day retention. Visit [anonymily.com/upgrade](https://anonymily.com/upgrade) to subscribe.
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -38,6 +38,8 @@ npm install -g @anonymilyhq/cli
|
|
|
38
38
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
41
|
+
**No account or signup required** — works immediately with free tier (50 requests, 24h retention).
|
|
42
|
+
|
|
41
43
|
```bash
|
|
42
44
|
# Start listening — generates a random endpoint ID automatically
|
|
43
45
|
npx @anonymilyhq/cli listen 3000
|
|
@@ -45,6 +47,7 @@ npx @anonymilyhq/cli listen 3000
|
|
|
45
47
|
# Output:
|
|
46
48
|
# 🚀 Anonymily CLI is running!
|
|
47
49
|
# Forwarding: https://api.anonymily.com/h/xk92bzte ➔ http://127.0.0.1:3000
|
|
50
|
+
# Tier: 🆓 FREE | Storage: 0/50 | Retention: 24 hours
|
|
48
51
|
# Waiting for requests to arrive...
|
|
49
52
|
```
|
|
50
53
|
|
|
@@ -109,19 +112,51 @@ export PRO_API_KEY=<your-pro-api-key>
|
|
|
109
112
|
|
|
110
113
|
---
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
### `feedback <rating> [message]`
|
|
116
|
+
|
|
117
|
+
Submit feedback about the Anonymily CLI directly from your terminal.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
anonymily feedback <rating> [message]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Parameter | Description |
|
|
124
|
+
|-----------|-------------|
|
|
125
|
+
| `<rating>` | **Required.** Rating from 1-5 (1=Poor, 5=Excellent) |
|
|
126
|
+
| `[message]` | Optional feedback message |
|
|
113
127
|
|
|
114
|
-
|
|
128
|
+
**Examples:**
|
|
129
|
+
```bash
|
|
130
|
+
# Quick rating
|
|
131
|
+
anonymily feedback 5
|
|
132
|
+
|
|
133
|
+
# Rating with message
|
|
134
|
+
anonymily feedback 4 "Great tool! Would love to see request filtering."
|
|
135
|
+
|
|
136
|
+
# Detailed feedback
|
|
137
|
+
anonymily feedback 5 "The SSE reconnection works perfectly. No issues so far!"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Your feedback helps us improve Anonymily. All submissions are anonymous unless you're logged in via the web dashboard.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Upgrading to Pro (₹750/month)
|
|
145
|
+
|
|
146
|
+
To get Pro limits (500 requests, 30-day retention), you need a **paid Pro subscription** at [anonymily.com/upgrade](https://anonymily.com/upgrade). This is an account-level subscription — all your claimed hooks get Pro limits automatically.
|
|
115
147
|
|
|
116
148
|
**Workflow:**
|
|
117
|
-
1.
|
|
118
|
-
2. Subscribe to Pro at [anonymily.com/upgrade](https://anonymily.com/upgrade)
|
|
119
|
-
3. Open the dashboard,
|
|
120
|
-
4.
|
|
149
|
+
1. Create an account at [anonymily.com/signup](https://anonymily.com/signup) (free)
|
|
150
|
+
2. Subscribe to Pro at [anonymily.com/upgrade](https://anonymily.com/upgrade) (₹750/month)
|
|
151
|
+
3. Open the dashboard, generate or use a custom hook ID
|
|
152
|
+
4. Click "Claim for Pro" to associate the hook with your account
|
|
153
|
+
5. Run the CLI with the same hook ID:
|
|
121
154
|
```bash
|
|
122
155
|
npx @anonymilyhq/cli listen 3000 --id your-claimed-hook
|
|
123
156
|
```
|
|
124
|
-
|
|
157
|
+
6. All Pro limits apply automatically — 500 requests, 30-day history
|
|
158
|
+
|
|
159
|
+
**Note:** Account creation is free, but Pro features require a paid subscription.
|
|
125
160
|
|
|
126
161
|
---
|
|
127
162
|
|
|
@@ -203,6 +238,10 @@ npx @anonymilyhq/cli listen 4000
|
|
|
203
238
|
|
|
204
239
|
---
|
|
205
240
|
|
|
241
|
+
## Changelog
|
|
242
|
+
|
|
243
|
+
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
|
|
244
|
+
|
|
206
245
|
## Contributing
|
|
207
246
|
|
|
208
247
|
Issues and pull requests are welcome. Open an issue first to discuss any significant changes.
|
package/bin/cli.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ProApiError,
|
|
13
13
|
} from '../lib/proRegister.js';
|
|
14
14
|
import { logger } from '../lib/logger.js';
|
|
15
|
+
import { submitFeedback } from '../lib/feedback.js';
|
|
15
16
|
|
|
16
17
|
// Point this to your live production backend URL
|
|
17
18
|
const API_URL = process.env.ANONYMILY_API_URL || 'https://api.anonymily.com';
|
|
@@ -19,7 +20,7 @@ const API_URL = process.env.ANONYMILY_API_URL || 'https://api.anonymily.com';
|
|
|
19
20
|
program
|
|
20
21
|
.name('anonymily')
|
|
21
22
|
.description('Forward webhooks from Anonymily directly to your local machine.')
|
|
22
|
-
.version('1.
|
|
23
|
+
.version('1.1.1');
|
|
23
24
|
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
25
26
|
// listen
|
|
@@ -89,5 +90,37 @@ configCmd
|
|
|
89
90
|
);
|
|
90
91
|
});
|
|
91
92
|
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// feedback
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
program
|
|
97
|
+
.command('feedback')
|
|
98
|
+
.description('Submit feedback about Anonymily CLI')
|
|
99
|
+
.argument('<rating>', 'Rating from 1-5 (1=Poor, 5=Excellent)')
|
|
100
|
+
.argument('[message]', 'Optional feedback message')
|
|
101
|
+
.action(async (rating, message) => {
|
|
102
|
+
const numRating = parseInt(rating, 10);
|
|
103
|
+
|
|
104
|
+
if (isNaN(numRating) || numRating < 1 || numRating > 5) {
|
|
105
|
+
logger.error('Rating must be a number between 1 and 5.');
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
logger.dim('Submitting feedback...');
|
|
110
|
+
const result = await submitFeedback(API_URL, numRating, message);
|
|
111
|
+
|
|
112
|
+
if (result.success) {
|
|
113
|
+
logger.success(
|
|
114
|
+
`\n✅ Thank you for your feedback! (ID: ${result.id || 'N/A'})\n`,
|
|
115
|
+
);
|
|
116
|
+
logger.raw(
|
|
117
|
+
'Your input helps us improve Anonymily. 🙏\n',
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
logger.error('Failed to submit feedback. Please try again later.');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
92
125
|
program.parse();
|
|
93
126
|
|
package/lib/feedback.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Submit feedback to the Anonymily backend.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} apiUrl - Base API URL
|
|
7
|
+
* @param {number} rating - Rating from 1-5
|
|
8
|
+
* @param {string} message - Optional feedback message
|
|
9
|
+
* @returns {Promise<{success: boolean, id?: string}>}
|
|
10
|
+
*/
|
|
11
|
+
export async function submitFeedback(apiUrl, rating, message = '') {
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch(`${apiUrl}/feedback`, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
rating,
|
|
20
|
+
message: message || undefined,
|
|
21
|
+
pagePath: 'cli',
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const errorText = await response.text();
|
|
27
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const result = await response.json();
|
|
31
|
+
return result;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
logger.error(`Failed to submit feedback: ${error.message}`);
|
|
34
|
+
return { success: false };
|
|
35
|
+
}
|
|
36
|
+
}
|
package/lib/forwarder.js
CHANGED
|
@@ -33,16 +33,53 @@ function ensureContentType(headers, body) {
|
|
|
33
33
|
return headers;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Fetch tier information for a hook ID from the backend.
|
|
38
|
+
*/
|
|
39
|
+
async function fetchTierInfo(apiUrl, hookId) {
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetch(`${apiUrl}/history/${hookId}`);
|
|
42
|
+
if (!response.ok) return null;
|
|
43
|
+
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
return {
|
|
46
|
+
tier: data.tier || 'free',
|
|
47
|
+
requestCount: data.requests?.length || 0,
|
|
48
|
+
maxRequests: data.tier === 'pro' ? 500 : 50,
|
|
49
|
+
retention: data.tier === 'pro' ? '30 days' : '24 hours',
|
|
50
|
+
};
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function startForwarding(apiUrl, hookId, port) {
|
|
37
57
|
const webhookUrl = `${apiUrl}/h/${hookId}`;
|
|
38
58
|
const localUrl = `http://127.0.0.1:${port}`;
|
|
39
59
|
|
|
40
60
|
logger.success(pc.bold(`\n🚀 Anonymily CLI is running!`));
|
|
41
61
|
logger.raw(`\nForwarding: ${pc.cyan(webhookUrl)} ➔ ${pc.cyan(localUrl)}`);
|
|
42
|
-
|
|
62
|
+
|
|
63
|
+
// Fetch and display tier information
|
|
64
|
+
const tierInfo = await fetchTierInfo(apiUrl, hookId);
|
|
65
|
+
if (tierInfo) {
|
|
66
|
+
const tierColor = tierInfo.tier === 'pro' ? pc.green : pc.yellow;
|
|
67
|
+
const tierBadge = tierInfo.tier === 'pro' ? '✨ PRO' : '🆓 FREE';
|
|
68
|
+
logger.raw(`Tier: ${tierColor(pc.bold(tierBadge))} | Storage: ${tierInfo.requestCount}/${tierInfo.maxRequests} | Retention: ${tierInfo.retention}`);
|
|
69
|
+
|
|
70
|
+
if (tierInfo.tier === 'free') {
|
|
71
|
+
logger.dim(`\n💡 Upgrade to Pro for 500 requests + 30-day retention at https://anonymily.com/upgrade`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
logger.dim(`Waiting for requests to arrive...`);
|
|
76
|
+
logger.dim(`💬 Enjoying the CLI? Run 'anonymily feedback 5' to let us know!\n`);
|
|
43
77
|
|
|
44
78
|
const es = new EventSourceConstructor(`${apiUrl}/stream/${hookId}`);
|
|
45
79
|
|
|
80
|
+
let requestCount = tierInfo?.requestCount || 0;
|
|
81
|
+
const maxRequests = tierInfo?.maxRequests || 50;
|
|
82
|
+
|
|
46
83
|
es.onmessage = async (event) => {
|
|
47
84
|
try {
|
|
48
85
|
const reqData = JSON.parse(event.data);
|
|
@@ -61,7 +98,12 @@ export function startForwarding(apiUrl, hookId, port) {
|
|
|
61
98
|
const queryString = new URLSearchParams(query || {}).toString();
|
|
62
99
|
const fullLocalUrl = queryString ? `${localUrl}?${queryString}` : localUrl;
|
|
63
100
|
|
|
64
|
-
|
|
101
|
+
// Increment request count and show progress
|
|
102
|
+
requestCount++;
|
|
103
|
+
const progress = `[${requestCount}/${maxRequests}]`;
|
|
104
|
+
const progressColor = requestCount > maxRequests * 0.8 ? pc.red : pc.dim;
|
|
105
|
+
|
|
106
|
+
logger.warn(`[${new Date().toLocaleTimeString()}] ⚡ Incoming ${method} request ${progressColor(progress)}...`);
|
|
65
107
|
|
|
66
108
|
const response = await fetch(fullLocalUrl, {
|
|
67
109
|
method,
|
|
@@ -71,6 +113,13 @@ export function startForwarding(apiUrl, hookId, port) {
|
|
|
71
113
|
|
|
72
114
|
const statusColor = response.ok ? pc.green : pc.red;
|
|
73
115
|
logger.raw(` └─ Forwarded to localhost | Status: ${statusColor(response.status)}\n`);
|
|
116
|
+
|
|
117
|
+
// Warn when approaching tier limit
|
|
118
|
+
if (requestCount === maxRequests) {
|
|
119
|
+
logger.warn(`⚠️ Tier limit reached (${maxRequests} requests). Older requests will be purged.\n`);
|
|
120
|
+
} else if (requestCount === Math.floor(maxRequests * 0.9)) {
|
|
121
|
+
logger.warn(`⚠️ 90% of tier limit reached. Consider upgrading to Pro for 500 requests.\n`);
|
|
122
|
+
}
|
|
74
123
|
} catch (err) {
|
|
75
124
|
logger.error(` └─ Error forwarding: ${err.message}`);
|
|
76
125
|
logger.dim(` Make sure your local server is actually running on port ${port}\n`);
|