@bagalobsta/revenue-monitor 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/bin/revenue.js +61 -0
- package/lib/index.js +48 -0
- package/package.json +35 -0
package/bin/revenue.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { RevenueMonitor } = require('../lib/index.js');
|
|
6
|
+
|
|
7
|
+
const monitor = new RevenueMonitor();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('revenue')
|
|
11
|
+
.version('1.0.0')
|
|
12
|
+
.description('Revenue tracker for your projects');
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('status <amount> [goal]')
|
|
16
|
+
.description('Show revenue status (amount in euros, goal defaults to 800)')
|
|
17
|
+
.action((amount, goal = 800) => {
|
|
18
|
+
const current = parseFloat(amount);
|
|
19
|
+
const goalAmount = parseFloat(goal);
|
|
20
|
+
const days = monitor.daysElapsed();
|
|
21
|
+
|
|
22
|
+
const projection = monitor.projectRevenue(current, days, goalAmount);
|
|
23
|
+
|
|
24
|
+
console.log(chalk.cyan(`\nš° Revenue Status\n`));
|
|
25
|
+
console.log(`Current: ${chalk.green(monitor.formatRevenue(current))}`);
|
|
26
|
+
console.log(`Goal: ${monitor.formatRevenue(goalAmount)}`);
|
|
27
|
+
console.log(`Days elapsed: ${days}`);
|
|
28
|
+
console.log(`Daily rate: ${chalk.yellow(monitor.formatRevenue(parseFloat(projection.dailyRate)))}/day`);
|
|
29
|
+
console.log(`Projected (21 days): ${chalk.yellow(monitor.formatRevenue(projection.projected))}`);
|
|
30
|
+
|
|
31
|
+
if (projection.onTrack) {
|
|
32
|
+
console.log(chalk.green(`ā
ON TRACK! Need ā¬${projection.neededPerDay}/day`));
|
|
33
|
+
} else {
|
|
34
|
+
console.log(chalk.red(`ā Behind pace. Need ā¬${projection.neededPerDay}/day`));
|
|
35
|
+
}
|
|
36
|
+
console.log(`Days remaining: ${projection.daysRemaining}\n`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('milestone')
|
|
41
|
+
.description('Show milestone progress')
|
|
42
|
+
.action(() => {
|
|
43
|
+
const milestones = monitor.getMilestones();
|
|
44
|
+
console.log(chalk.cyan('\nšÆ Milestones\n'));
|
|
45
|
+
milestones.forEach(m => {
|
|
46
|
+
console.log(`${m.label.padEnd(25)} ${monitor.formatRevenue(m.amount)}`);
|
|
47
|
+
});
|
|
48
|
+
console.log();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
program
|
|
52
|
+
.command('needed <goal> <days>')
|
|
53
|
+
.description('Calculate daily rate needed (goal in euros, days remaining)')
|
|
54
|
+
.action((goal, days) => {
|
|
55
|
+
const dailyNeeded = parseFloat(goal) / parseInt(days);
|
|
56
|
+
console.log(chalk.cyan(`\nš Daily Target\n`));
|
|
57
|
+
console.log(`To reach ā¬${goal} in ${days} days:`);
|
|
58
|
+
console.log(`Need: ${chalk.yellow(monitor.formatRevenue(dailyNeeded))}/day\n`);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
program.parse(process.argv);
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class RevenueMonitor {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.startDate = new Date('2026-02-01');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Calculate days elapsed
|
|
7
|
+
daysElapsed() {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const diff = now - this.startDate;
|
|
10
|
+
return Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Project revenue at current rate
|
|
14
|
+
projectRevenue(currentRevenue, daysElapsed, goalAmount, goalDays = 21) {
|
|
15
|
+
const perDay = currentRevenue / daysElapsed;
|
|
16
|
+
const projectedEnd = perDay * goalDays;
|
|
17
|
+
const onTrack = projectedEnd >= goalAmount;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
currentRevenue,
|
|
21
|
+
daysElapsed,
|
|
22
|
+
dailyRate: perDay.toFixed(2),
|
|
23
|
+
projected: Math.round(projectedEnd),
|
|
24
|
+
goal: goalAmount,
|
|
25
|
+
onTrack,
|
|
26
|
+
daysRemaining: goalDays - daysElapsed,
|
|
27
|
+
neededPerDay: ((goalAmount - currentRevenue) / (goalDays - daysElapsed)).toFixed(2)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Milestone tracker
|
|
32
|
+
getMilestones() {
|
|
33
|
+
return [
|
|
34
|
+
{ amount: 100, label: 'First ā¬100' },
|
|
35
|
+
{ amount: 250, label: 'Quarter of the way' },
|
|
36
|
+
{ amount: 400, label: 'Half goal (ā¬800)' },
|
|
37
|
+
{ amount: 600, label: 'Ready for Mac mini' },
|
|
38
|
+
{ amount: 800, label: 'Goal reached! š' }
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Format revenue display
|
|
43
|
+
formatRevenue(amount) {
|
|
44
|
+
return `ā¬${amount.toLocaleString()}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { RevenueMonitor };
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bagalobsta/revenue-monitor",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Real-time revenue tracker for side projects. Track sales, downloads, and progress toward goals.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"revenue": "bin/revenue.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo 'ready'"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"revenue",
|
|
14
|
+
"tracking",
|
|
15
|
+
"sales",
|
|
16
|
+
"analytics",
|
|
17
|
+
"goals"
|
|
18
|
+
],
|
|
19
|
+
"author": "Bagalobsta <bagalobsta@protonmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/bagalobsta/revenue-monitor.git"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"commander": "^11.1.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=14.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|