ragebuttonapi 1.0.0 → 1.0.2
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/{index.js → api_library.js} +21 -16
- package/{cli.js → cli_entrypoint.js} +26 -44
- package/package.json +1 -29
- package/npm-cli.tar.gz +0 -0
- package/npm-cli.zip +0 -0
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* const rageApi = require('ragebuttonapi');
|
|
6
6
|
*
|
|
7
7
|
* // one-time init
|
|
8
|
-
* rageApi.init({
|
|
8
|
+
* rageApi.init({ apiKey: 'rbapi_xxx' });
|
|
9
9
|
*
|
|
10
10
|
* // register rage
|
|
11
11
|
* await rageApi.rage('this stupid bug omg');
|
|
12
12
|
*
|
|
13
|
-
* // or inline config
|
|
14
|
-
* await rageApi.rage('why', {
|
|
13
|
+
* // or inline config override
|
|
14
|
+
* await rageApi.rage('why', { apiKey: '...' });
|
|
15
15
|
*
|
|
16
16
|
* // get global stats
|
|
17
17
|
* const stats = await rageApi.stats();
|
|
@@ -26,9 +26,9 @@ const https = require('https');
|
|
|
26
26
|
const http = require('http');
|
|
27
27
|
const url = require('url');
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
const DEFAULT_SERVER = 'https://ragebutton.unaux.com';
|
|
30
|
+
let _globalConfig = { url: DEFAULT_SERVER, apiKey: null };
|
|
30
31
|
|
|
31
|
-
// ─── low-level request helper ────────────────────────────────────────────────
|
|
32
32
|
function request(endpoint, { method = 'GET', body = null } = {}) {
|
|
33
33
|
return new Promise((resolve, reject) => {
|
|
34
34
|
const parsed = url.parse(endpoint);
|
|
@@ -45,7 +45,9 @@ function request(endpoint, { method = 'GET', body = null } = {}) {
|
|
|
45
45
|
path : parsed.path,
|
|
46
46
|
method,
|
|
47
47
|
headers : {
|
|
48
|
-
'User-Agent': '
|
|
48
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
49
|
+
'Accept': 'application/json, text/plain, */*',
|
|
50
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
49
51
|
...(payload ? {
|
|
50
52
|
'Content-Type' : 'application/x-www-form-urlencoded',
|
|
51
53
|
'Content-Length': Buffer.byteLength(payload),
|
|
@@ -68,7 +70,14 @@ function request(endpoint, { method = 'GET', body = null } = {}) {
|
|
|
68
70
|
resolve(json);
|
|
69
71
|
}
|
|
70
72
|
} catch {
|
|
71
|
-
|
|
73
|
+
// Detect if server is running on InfinityFree / Unaux and blocking programmatic calls
|
|
74
|
+
if (data.includes('__test') || data.includes('aes.js') || data.includes('Javascript to work') || data.includes('testcookie')) {
|
|
75
|
+
reject(new Error(
|
|
76
|
+
'API request blocked by your hosting provider (Unaux/InfinityFree). Free hosts use a browser verification cookie (aes.js) that blocks standard CLI/API client scripts. To fix this, consider deploying your API on developer-friendly platforms like Koyeb, Render, Railway, or Vercel (for serverless PHP) which do not block API calls.'
|
|
77
|
+
));
|
|
78
|
+
} else {
|
|
79
|
+
reject(new Error(`bad response from server (status ${res.statusCode}). is ur server up?`));
|
|
80
|
+
}
|
|
72
81
|
}
|
|
73
82
|
});
|
|
74
83
|
});
|
|
@@ -79,13 +88,11 @@ function request(endpoint, { method = 'GET', body = null } = {}) {
|
|
|
79
88
|
});
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
// ─── resolve config, merging inline overrides ────────────────────────────────
|
|
83
91
|
function resolveConfig(inline = {}) {
|
|
84
92
|
const cfg = {
|
|
85
|
-
url : inline.url ?? _globalConfig.url,
|
|
93
|
+
url : inline.url ?? _globalConfig.url ?? DEFAULT_SERVER,
|
|
86
94
|
apiKey: inline.apiKey ?? _globalConfig.apiKey,
|
|
87
95
|
};
|
|
88
|
-
if (!cfg.url) throw new Error('ragebuttonapi: server url is required. call rageApi.init({ url }) or pass it inline.');
|
|
89
96
|
if (!cfg.apiKey) throw new Error('ragebuttonapi: apiKey is required. get it from ur dashboard.');
|
|
90
97
|
return { ...cfg, url: cfg.url.replace(/\/$/, '') };
|
|
91
98
|
}
|
|
@@ -94,7 +101,7 @@ function resolveConfig(inline = {}) {
|
|
|
94
101
|
|
|
95
102
|
/**
|
|
96
103
|
* One-time global config. call this at app startup.
|
|
97
|
-
* @param {{ url
|
|
104
|
+
* @param {{ url?: string, apiKey: string }} config
|
|
98
105
|
*/
|
|
99
106
|
function init(config = {}) {
|
|
100
107
|
if (config.url) _globalConfig.url = config.url.replace(/\/$/, '');
|
|
@@ -125,8 +132,7 @@ async function rage(reason, config = {}) {
|
|
|
125
132
|
* @returns {Promise<{total_rages, today_rages, user_count}>}
|
|
126
133
|
*/
|
|
127
134
|
async function stats(config = {}) {
|
|
128
|
-
const serverUrl = config.url ?? _globalConfig.url;
|
|
129
|
-
if (!serverUrl) throw new Error('ragebuttonapi: url is required for stats()');
|
|
135
|
+
const serverUrl = config.url ?? _globalConfig.url ?? DEFAULT_SERVER;
|
|
130
136
|
return request(`${serverUrl.replace(/\/$/, '')}/api/stats.php`);
|
|
131
137
|
}
|
|
132
138
|
|
|
@@ -137,9 +143,8 @@ async function stats(config = {}) {
|
|
|
137
143
|
* @returns {Promise<{ feed: Array<{user, reason, time_ago}> }>}
|
|
138
144
|
*/
|
|
139
145
|
async function feed(limit = 10, config = {}) {
|
|
140
|
-
const serverUrl = config.url ?? _globalConfig.url;
|
|
141
|
-
if (!serverUrl) throw new Error('ragebuttonapi: url is required for feed()');
|
|
146
|
+
const serverUrl = config.url ?? _globalConfig.url ?? DEFAULT_SERVER;
|
|
142
147
|
return request(`${serverUrl.replace(/\/$/, '')}/api/feed.php?limit=${limit}`);
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
module.exports = { init, rage, stats, feed };
|
|
150
|
+
module.exports = { init, rage, stats, feed };
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* install: npm install -g ragebuttonapi
|
|
5
5
|
* usage:
|
|
6
6
|
* rage → register a rage (prompts for reason)
|
|
7
|
-
* rage setup → configure server
|
|
7
|
+
* rage setup → configure api key (server is automatically set)
|
|
8
8
|
* rage "this bug is insane" → rage with inline reason
|
|
9
9
|
* rage --reason "msg" → rage with reason flag
|
|
10
10
|
* rage stats → global stats
|
|
@@ -21,23 +21,28 @@ const os = require('os');
|
|
|
21
21
|
const rageApi = require('./index.js');
|
|
22
22
|
|
|
23
23
|
const CONFIG_PATH = path.join(os.homedir(), '.ragebuttonapirc');
|
|
24
|
-
const VERSION = '1.0.
|
|
24
|
+
const VERSION = '1.0.1';
|
|
25
|
+
const DEFAULT_SERVER = 'https://ragebutton.unaux.com';
|
|
25
26
|
|
|
26
27
|
// ─── Config file helpers ──────────────────────────────────────────────────────
|
|
27
28
|
function loadConfig() {
|
|
28
29
|
try {
|
|
29
30
|
if (fs.existsSync(CONFIG_PATH)) {
|
|
30
|
-
|
|
31
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|
32
|
+
// Ensure there is always a default url
|
|
33
|
+
if (!parsed.url) {
|
|
34
|
+
parsed.url = DEFAULT_SERVER;
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
31
37
|
}
|
|
32
38
|
} catch { /* corrupt config, treat as missing */ }
|
|
33
|
-
return {};
|
|
39
|
+
return { url: DEFAULT_SERVER };
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
function saveConfig(cfg) {
|
|
37
43
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
// ─── Colors (no deps, raw ANSI) ───────────────────────────────────────────────
|
|
41
46
|
const c = {
|
|
42
47
|
reset : '\x1b[0m',
|
|
43
48
|
bold : '\x1b[1m',
|
|
@@ -64,7 +69,6 @@ ${dim('────────────────────────
|
|
|
64
69
|
`);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
// ─── Prompts (pure readline, no deps) ────────────────────────────────────────
|
|
68
72
|
function prompt(question) {
|
|
69
73
|
return new Promise(resolve => {
|
|
70
74
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -75,7 +79,6 @@ function prompt(question) {
|
|
|
75
79
|
function promptPassword(question) {
|
|
76
80
|
return new Promise(resolve => {
|
|
77
81
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
78
|
-
// hide input
|
|
79
82
|
process.stdout.write(question);
|
|
80
83
|
process.stdin.setRawMode?.(true);
|
|
81
84
|
let pass = '';
|
|
@@ -104,18 +107,10 @@ function promptPassword(question) {
|
|
|
104
107
|
});
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
// ─── Setup command ────────────────────────────────────────────────────────────
|
|
108
110
|
async function cmdSetup(existing = {}) {
|
|
109
111
|
logo();
|
|
110
|
-
console.log(`${acc('Setup')} —
|
|
111
|
-
|
|
112
|
-
const defaultUrl = existing.url || '';
|
|
113
|
-
let serverUrl = await prompt(
|
|
114
|
-
`Server URL ${defaultUrl ? dim(`[${defaultUrl}]`) : ''}: `
|
|
115
|
-
);
|
|
116
|
-
if (!serverUrl && defaultUrl) serverUrl = defaultUrl;
|
|
117
|
-
if (!serverUrl) { console.log(err('\nurls cant be empty. try again.')); process.exit(1); }
|
|
118
|
-
serverUrl = serverUrl.replace(/\/$/, '');
|
|
112
|
+
console.log(`${acc('Setup')} — let's get u configured fr\n`);
|
|
113
|
+
console.log(`${dim('Server is locked to default:')} ${hl(DEFAULT_SERVER)}`);
|
|
119
114
|
|
|
120
115
|
const defaultKey = existing.apiKey ? '***' + existing.apiKey.slice(-4) : '';
|
|
121
116
|
console.log(`\nAPI Key (from ur dashboard)${defaultKey ? dim(` [${defaultKey}]`) : ''}:`);
|
|
@@ -123,29 +118,27 @@ async function cmdSetup(existing = {}) {
|
|
|
123
118
|
try {
|
|
124
119
|
apiKey = await promptPassword('> ');
|
|
125
120
|
} catch {
|
|
126
|
-
// fallback if raw mode unavailable (piped stdin etc)
|
|
127
121
|
apiKey = await prompt('API Key: ');
|
|
128
122
|
}
|
|
129
123
|
if (!apiKey && existing.apiKey) apiKey = existing.apiKey;
|
|
130
124
|
if (!apiKey) { console.log(err('\napi key cant be empty bestie.')); process.exit(1); }
|
|
131
125
|
|
|
132
|
-
const cfg = { url:
|
|
126
|
+
const cfg = { url: DEFAULT_SERVER, apiKey };
|
|
133
127
|
saveConfig(cfg);
|
|
134
128
|
|
|
135
129
|
console.log(`\n${ok('✓')} saved to ${dim(CONFIG_PATH)}`);
|
|
136
|
-
console.log(
|
|
137
|
-
console.log(` key: ${dim('***' + apiKey.slice(-4))}\n`);
|
|
130
|
+
console.log(` server: ${hl(DEFAULT_SERVER)}`);
|
|
131
|
+
console.log(` key : ${dim('***' + apiKey.slice(-4))}\n`);
|
|
138
132
|
console.log(ok(`all done! run ${hl('rage')} anytime to register ur suffering 💢\n`));
|
|
139
133
|
}
|
|
140
134
|
|
|
141
|
-
// ─── Rage command ─────────────────────────────────────────────────────────────
|
|
142
135
|
async function cmdRage(reason, cfg) {
|
|
143
|
-
|
|
136
|
+
const serverUrl = cfg.url || DEFAULT_SERVER;
|
|
137
|
+
if (!cfg.apiKey) {
|
|
144
138
|
console.log(`\n${err('not configured yet fr.')} run ${hl('rage setup')} first.\n`);
|
|
145
139
|
process.exit(1);
|
|
146
140
|
}
|
|
147
141
|
|
|
148
|
-
// ask for reason if not provided inline
|
|
149
142
|
if (reason === null || reason === undefined) {
|
|
150
143
|
reason = await prompt(`${dim('what broke? (enter to skip):')} `);
|
|
151
144
|
}
|
|
@@ -153,10 +146,10 @@ async function cmdRage(reason, cfg) {
|
|
|
153
146
|
process.stdout.write(`\n${acc('💢')} registering ur rage...`);
|
|
154
147
|
|
|
155
148
|
try {
|
|
156
|
-
rageApi.init({ url:
|
|
149
|
+
rageApi.init({ url: serverUrl, apiKey: cfg.apiKey });
|
|
157
150
|
const res = await rageApi.rage(reason, { source: 'cli' });
|
|
158
151
|
|
|
159
|
-
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
152
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
160
153
|
|
|
161
154
|
console.log(`\n ${acc('💢 RAGE REGISTERED')}\n`);
|
|
162
155
|
console.log(` ${ok('✓')} message: ${dim(res.message)}`);
|
|
@@ -187,7 +180,7 @@ async function cmdRage(reason, cfg) {
|
|
|
187
180
|
} else if (e.code === 'daily_limit') {
|
|
188
181
|
console.log(`\n ${err('😤 daily limit hit')} — 24/24 rages today. iconic. come back tomorrow.\n`);
|
|
189
182
|
} else if (e.code === 'ECONNREFUSED' || e.code === 'ENOTFOUND') {
|
|
190
|
-
console.log(`\n ${err('❌ couldnt connect')} — is
|
|
183
|
+
console.log(`\n ${err('❌ couldnt connect')} — is the server down? (${dim(serverUrl)})\n`);
|
|
191
184
|
} else {
|
|
192
185
|
console.log(`\n ${err('💀 error:')} ${e.message}\n`);
|
|
193
186
|
}
|
|
@@ -195,14 +188,10 @@ async function cmdRage(reason, cfg) {
|
|
|
195
188
|
}
|
|
196
189
|
}
|
|
197
190
|
|
|
198
|
-
// ─── Stats command ────────────────────────────────────────────────────────────
|
|
199
191
|
async function cmdStats(cfg) {
|
|
200
|
-
|
|
201
|
-
console.log(`\n${err('no url configured.')} run ${hl('rage setup')} first.\n`);
|
|
202
|
-
process.exit(1);
|
|
203
|
-
}
|
|
192
|
+
const serverUrl = cfg.url || DEFAULT_SERVER;
|
|
204
193
|
try {
|
|
205
|
-
const res = await rageApi.stats({ url:
|
|
194
|
+
const res = await rageApi.stats({ url: serverUrl });
|
|
206
195
|
logo();
|
|
207
196
|
console.log(` ${acc('📊 global stats')}\n`);
|
|
208
197
|
console.log(` total rages: ${hl(Number(res.total_rages).toLocaleString())}`);
|
|
@@ -215,14 +204,10 @@ async function cmdStats(cfg) {
|
|
|
215
204
|
}
|
|
216
205
|
}
|
|
217
206
|
|
|
218
|
-
// ─── Feed command ─────────────────────────────────────────────────────────────
|
|
219
207
|
async function cmdFeed(limit, cfg) {
|
|
220
|
-
|
|
221
|
-
console.log(`\n${err('no url configured.')} run ${hl('rage setup')} first.\n`);
|
|
222
|
-
process.exit(1);
|
|
223
|
-
}
|
|
208
|
+
const serverUrl = cfg.url || DEFAULT_SERVER;
|
|
224
209
|
try {
|
|
225
|
-
const res = await rageApi.feed(limit, { url:
|
|
210
|
+
const res = await rageApi.feed(limit, { url: serverUrl });
|
|
226
211
|
const feed = res.feed || [];
|
|
227
212
|
logo();
|
|
228
213
|
console.log(` ${acc('🔴 live rage feed')} ${dim(`(last ${feed.length})`)} \n`);
|
|
@@ -245,12 +230,11 @@ async function cmdFeed(limit, cfg) {
|
|
|
245
230
|
}
|
|
246
231
|
}
|
|
247
232
|
|
|
248
|
-
// ─── Help ─────────────────────────────────────────────────────────────────────
|
|
249
233
|
function showHelp() {
|
|
250
234
|
logo();
|
|
251
235
|
console.log(` ${acc('Commands')}\n`);
|
|
252
236
|
console.log(` ${hl('rage')} → register rage (asks reason interactively)`);
|
|
253
|
-
console.log(` ${hl('rage setup')} → configure
|
|
237
|
+
console.log(` ${hl('rage setup')} → configure api key`);
|
|
254
238
|
console.log(` ${hl('rage stats')} → global stats`);
|
|
255
239
|
console.log(` ${hl('rage feed')} → live rage feed`);
|
|
256
240
|
console.log(` ${hl('rage "reason here"')} → rage with inline reason`);
|
|
@@ -263,7 +247,6 @@ function showHelp() {
|
|
|
263
247
|
console.log('');
|
|
264
248
|
}
|
|
265
249
|
|
|
266
|
-
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
267
250
|
async function main() {
|
|
268
251
|
const args = process.argv.slice(2);
|
|
269
252
|
const cfg = loadConfig();
|
|
@@ -289,7 +272,6 @@ async function main() {
|
|
|
289
272
|
}
|
|
290
273
|
|
|
291
274
|
// default: rage
|
|
292
|
-
// inline reason: first non-flag, non-subcommand arg
|
|
293
275
|
const inlineReason = args.find(a => !a.startsWith('-') && a !== 'rage');
|
|
294
276
|
|
|
295
277
|
let reason;
|
|
@@ -304,4 +286,4 @@ async function main() {
|
|
|
304
286
|
main().catch(e => {
|
|
305
287
|
console.error(`\n${err('unexpected error:')} ${e.message}\n`);
|
|
306
288
|
process.exit(1);
|
|
307
|
-
});
|
|
289
|
+
});
|
package/package.json
CHANGED
|
@@ -1,29 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ragebuttonapi",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "official npm package + cli for RAGEBUTTONAPI™ — register developer rage from ur terminal or node app. no account needed for anon rages.",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"rage": "cli.js",
|
|
8
|
-
"npm-cli": "cli.js",
|
|
9
|
-
"npmc": "cli.js"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"test": "node cli.js --help"
|
|
13
|
-
},
|
|
14
|
-
"keywords": [
|
|
15
|
-
"rage",
|
|
16
|
-
"developer",
|
|
17
|
-
"api",
|
|
18
|
-
"cli",
|
|
19
|
-
"fun",
|
|
20
|
-
"mental-health",
|
|
21
|
-
"programming",
|
|
22
|
-
"anger"
|
|
23
|
-
],
|
|
24
|
-
"author": "RAGEBUTTONAPI™",
|
|
25
|
-
"license": "MIT",
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=16.0.0"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
1
|
+
{"name":"ragebuttonapi","version":"1.0.2","description":"official npm package + cli for RAGEBUTTONAPI™ — register developer rage from ur terminal or node app. no account needed for anon rages.","main":"index.js","bin":{"rage":"./cli.js"},"scripts":{"test":"node cli.js --help"},"keywords":["rage","developer","api","cli","fun","mental-health","programming","anger"],"author":"RAGEBUTTONAPI™","license":"MIT","engines":{"node":">=16.0.0"},"dependencies":{}}
|
package/npm-cli.tar.gz
DELETED
|
Binary file
|
package/npm-cli.zip
DELETED
|
Binary file
|