@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 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, no sign-ups required to start. Just one command.
19
+ **No tunnels. No signup. No account required.** Just one command.
20
20
 
21
- > **Pro tip:** Create a free account at [anonymily.com](https://anonymily.com) and claim your endpoint to keep the same URL across sessions and unlock 500 requests / 30-day history retention with a Pro subscription.
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
- ## Account-Based Pro (Recommended)
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
- The modern way to get Pro limits is via an **account subscription** at [anonymily.com/upgrade](https://anonymily.com/upgrade). This gives your entire account Pro limits (₹750/month) — no per-hook configuration needed.
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. Sign up at [anonymily.com](https://anonymily.com)
118
- 2. Subscribe to Pro at [anonymily.com/upgrade](https://anonymily.com/upgrade)
119
- 3. Open the dashboard, copy your endpoint URL, and claim it to your account
120
- 4. Run the CLI with the same hook ID:
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
- 5. All Pro limits apply automatically — 500 requests, 30-day history
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.0.3');
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
 
@@ -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
- export function startForwarding(apiUrl, hookId, port) {
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
- logger.dim(`Waiting for requests to arrive...\n`);
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
- logger.warn(`[${new Date().toLocaleTimeString()}] Incoming ${method} request...`);
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`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anonymilyhq/cli",
3
- "version": "1.0.4",
3
+ "version": "1.1.1",
4
4
  "description": "CLI for Anonymily platform",
5
5
  "type": "module",
6
6
  "bin": {