omnibiofex 2.8.2 ā 2.8.3
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/package.json +1 -1
- package/src/commands/account.js +17 -12
- package/src/commands/earnings.js +20 -12
- package/src/commands/publish.js +18 -13
- package/src/firebase.js +80 -1
package/package.json
CHANGED
package/src/commands/account.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const open = require('open');
|
|
3
3
|
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
-
const { db,
|
|
4
|
+
const { db, getCurrentUserUid, getCurrentUserEmail } = require('../firebase');
|
|
5
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
6
6
|
const { collection, query, where, getDocs } = require('firebase/firestore');
|
|
7
7
|
|
|
@@ -61,22 +61,24 @@ async function usage() {
|
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Get user UID from stored token
|
|
65
|
+
const uid = getCurrentUserUid();
|
|
66
|
+
const email = getCurrentUserEmail();
|
|
67
|
+
|
|
68
|
+
if (!uid) {
|
|
69
|
+
console.error(chalk.red('ā Could not extract user ID from token.'));
|
|
70
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
const spinner = new PremiumSpinner('Fetching usage statistics');
|
|
65
75
|
spinner.start();
|
|
66
76
|
|
|
67
77
|
try {
|
|
68
|
-
const user = auth.currentUser;
|
|
69
|
-
|
|
70
|
-
if (!user) {
|
|
71
|
-
spinner.fail('Not authenticated');
|
|
72
|
-
console.error(chalk.red('Please run: obx login'));
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
78
|
// Fetch ALL missions (real data)
|
|
77
79
|
const allMissionsQuery = query(
|
|
78
80
|
collection(db, 'missions'),
|
|
79
|
-
where('uid', '==',
|
|
81
|
+
where('uid', '==', uid)
|
|
80
82
|
);
|
|
81
83
|
|
|
82
84
|
const allMissionsSnapshot = await getDocs(allMissionsQuery);
|
|
@@ -99,7 +101,7 @@ async function usage() {
|
|
|
99
101
|
// Fetch published missions for earnings
|
|
100
102
|
const publishedQuery = query(
|
|
101
103
|
collection(db, 'missions'),
|
|
102
|
-
where('uid', '==',
|
|
104
|
+
where('uid', '==', uid),
|
|
103
105
|
where('isPublished', '==', true)
|
|
104
106
|
);
|
|
105
107
|
|
|
@@ -122,7 +124,10 @@ async function usage() {
|
|
|
122
124
|
console.log(chalk.white.bold('š USAGE STATISTICS'));
|
|
123
125
|
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
124
126
|
|
|
125
|
-
console.log(chalk.
|
|
127
|
+
console.log(chalk.gray(` š¤ User: ${chalk.white(email || 'Unknown')}`));
|
|
128
|
+
console.log(chalk.gray(` š UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
129
|
+
|
|
130
|
+
console.log(chalk.white(`\n šÆ Total Missions: ${chalk.green(totalMissions)}`));
|
|
126
131
|
console.log(chalk.white(` ā
Completed: ${chalk.green(completedMissions)}`));
|
|
127
132
|
console.log(chalk.white(` ā³ Active: ${chalk.yellow(activeMissions)}`));
|
|
128
133
|
console.log(chalk.white(` ā½ RCC Spent: ${chalk.green(totalRCCSpent.toLocaleString())}`));
|
package/src/commands/earnings.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const {
|
|
3
|
-
const { db,
|
|
2
|
+
const { isAuthenticated } = require('../auth');
|
|
3
|
+
const { db, getCurrentUserUid, getCurrentUserEmail, isTokenValid } = require('../firebase');
|
|
4
4
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
5
|
const { collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
6
6
|
|
|
@@ -10,22 +10,24 @@ async function earnings() {
|
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// Get user UID from stored token (NOT from auth.currentUser)
|
|
14
|
+
const uid = getCurrentUserUid();
|
|
15
|
+
const email = getCurrentUserEmail();
|
|
16
|
+
|
|
17
|
+
if (!uid) {
|
|
18
|
+
console.error(chalk.red('ā Could not extract user ID from token.'));
|
|
19
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
const spinner = new PremiumSpinner('Fetching your earnings data');
|
|
14
24
|
spinner.start();
|
|
15
25
|
|
|
16
26
|
try {
|
|
17
|
-
const user = auth.currentUser;
|
|
18
|
-
|
|
19
|
-
if (!user) {
|
|
20
|
-
spinner.fail('Not authenticated');
|
|
21
|
-
console.error(chalk.red('Please run: obx login'));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
27
|
// Fetch real published missions with earnings data
|
|
26
28
|
const publishedQuery = query(
|
|
27
29
|
collection(db, 'missions'),
|
|
28
|
-
where('uid', '==',
|
|
30
|
+
where('uid', '==', uid),
|
|
29
31
|
where('isPublished', '==', true),
|
|
30
32
|
orderBy('publishedAt', 'desc'),
|
|
31
33
|
limit(100)
|
|
@@ -73,8 +75,11 @@ async function earnings() {
|
|
|
73
75
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
74
76
|
console.log(chalk.white.bold('š° EARNINGS DASHBOARD'));
|
|
75
77
|
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
78
|
+
|
|
79
|
+
console.log(chalk.gray(` š¤ User: ${chalk.white(email || 'Unknown')}`));
|
|
80
|
+
console.log(chalk.gray(` š UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
76
81
|
|
|
77
|
-
console.log(chalk.white.bold('š OVERVIEW'));
|
|
82
|
+
console.log(chalk.white.bold('\n\nš OVERVIEW'));
|
|
78
83
|
console.log(chalk.gray('ā'.repeat(60)));
|
|
79
84
|
console.log(chalk.white(`\n š° Total Earnings: ${chalk.green('ā¹' + totalEarnings.toLocaleString())}`));
|
|
80
85
|
console.log(chalk.white(` š
This Month: ${chalk.green('ā¹' + thisMonthEarnings.toLocaleString())}`));
|
|
@@ -112,6 +117,9 @@ async function earnings() {
|
|
|
112
117
|
console.log(chalk.white(` š° Earnings: ${chalk.green('ā¹' + (m.earnings || 0).toLocaleString())}`));
|
|
113
118
|
console.log(chalk.gray(` š
Published: ${publishedDate}`));
|
|
114
119
|
});
|
|
120
|
+
} else {
|
|
121
|
+
console.log(chalk.yellow('\n\n ā ļø No published research yet.'));
|
|
122
|
+
console.log(chalk.gray(' Run "obx publish" to publish your first research and start earning.\n'));
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
package/src/commands/publish.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('inquirer');
|
|
3
3
|
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
-
const { db,
|
|
4
|
+
const { db, getCurrentUserUid, getCurrentUserEmail } = require('../firebase');
|
|
5
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
6
6
|
const { collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
|
|
7
7
|
|
|
@@ -11,30 +11,35 @@ async function publish(missionId) {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// Get user UID from stored token
|
|
15
|
+
const uid = getCurrentUserUid();
|
|
16
|
+
const email = getCurrentUserEmail();
|
|
17
|
+
|
|
18
|
+
if (!uid) {
|
|
19
|
+
console.error(chalk.red('ā Could not extract user ID from token.'));
|
|
20
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
15
25
|
console.log(chalk.white.bold('š¤ PUBLISH RESEARCH'));
|
|
16
26
|
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
27
|
+
|
|
28
|
+
console.log(chalk.gray(` š¤ User: ${chalk.white(email || 'Unknown')}`));
|
|
29
|
+
console.log(chalk.gray(` š UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
17
30
|
|
|
18
31
|
// If no mission ID provided, fetch real missions from Firestore
|
|
19
32
|
if (!missionId) {
|
|
20
|
-
console.log(chalk.gray('
|
|
33
|
+
console.log(chalk.gray('\nFetching your completed missions...\n'));
|
|
21
34
|
|
|
22
35
|
const spinner = new PremiumSpinner('Loading missions from database');
|
|
23
36
|
spinner.start();
|
|
24
37
|
|
|
25
38
|
try {
|
|
26
|
-
const user = auth.currentUser;
|
|
27
|
-
|
|
28
|
-
if (!user) {
|
|
29
|
-
spinner.fail('Not authenticated');
|
|
30
|
-
console.error(chalk.red('Please run: obx login'));
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
39
|
// Fetch real completed missions from Firestore
|
|
35
40
|
const missionsQuery = query(
|
|
36
41
|
collection(db, 'missions'),
|
|
37
|
-
where('uid', '==',
|
|
42
|
+
where('uid', '==', uid),
|
|
38
43
|
where('status', '==', 'completed'),
|
|
39
44
|
where('isPublished', '==', false),
|
|
40
45
|
orderBy('createdAt', 'desc'),
|
|
@@ -140,8 +145,8 @@ async function publish(missionId) {
|
|
|
140
145
|
downloads: 0,
|
|
141
146
|
citations: 0,
|
|
142
147
|
earnings: 0,
|
|
143
|
-
authorName:
|
|
144
|
-
authorEmail:
|
|
148
|
+
authorName: email || 'Anonymous Researcher',
|
|
149
|
+
authorEmail: email || 'unknown@example.com'
|
|
145
150
|
});
|
|
146
151
|
|
|
147
152
|
spinner.succeed('Research published successfully!');
|
package/src/firebase.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { initializeApp, getApps } = require('firebase/app');
|
|
2
2
|
const { getAuth } = require('firebase/auth');
|
|
3
3
|
const { getFirestore } = require('firebase/firestore');
|
|
4
|
+
const Conf = require('conf');
|
|
4
5
|
|
|
5
6
|
const firebaseConfig = {
|
|
6
7
|
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
@@ -22,4 +23,82 @@ if (getApps().length === 0) {
|
|
|
22
23
|
const auth = getAuth(app);
|
|
23
24
|
const db = getFirestore(app);
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
// Shared Conf storage for tokens
|
|
27
|
+
const tokenStore = new Conf({
|
|
28
|
+
projectName: 'omnibiofex',
|
|
29
|
+
schema: {
|
|
30
|
+
token: { type: 'string' },
|
|
31
|
+
refreshToken: { type: 'string' },
|
|
32
|
+
expiresAt: { type: 'number' }
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Decode JWT token to extract user info
|
|
38
|
+
* @returns {Object|null} - { uid, email } or null if no token
|
|
39
|
+
*/
|
|
40
|
+
function decodeToken() {
|
|
41
|
+
const token = tokenStore.get('token');
|
|
42
|
+
if (!token) return null;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// JWT format: header.payload.signature
|
|
46
|
+
const parts = token.split('.');
|
|
47
|
+
if (parts.length !== 3) return null;
|
|
48
|
+
|
|
49
|
+
// Decode payload (base64url)
|
|
50
|
+
const payload = parts[1];
|
|
51
|
+
const decoded = Buffer.from(payload, 'base64').toString('utf8');
|
|
52
|
+
const data = JSON.parse(decoded);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
uid: data.user_id || data.sub,
|
|
56
|
+
email: data.email,
|
|
57
|
+
exp: data.exp
|
|
58
|
+
};
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get current user UID from stored token
|
|
66
|
+
* @returns {string|null} - User UID or null
|
|
67
|
+
*/
|
|
68
|
+
function getCurrentUserUid() {
|
|
69
|
+
const decoded = decodeToken();
|
|
70
|
+
return decoded ? decoded.uid : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get current user email from stored token
|
|
75
|
+
* @returns {string|null} - User email or null
|
|
76
|
+
*/
|
|
77
|
+
function getCurrentUserEmail() {
|
|
78
|
+
const decoded = decodeToken();
|
|
79
|
+
return decoded ? decoded.email : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if token is valid (not expired)
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
function isTokenValid() {
|
|
87
|
+
const decoded = decodeToken();
|
|
88
|
+
if (!decoded || !decoded.exp) return false;
|
|
89
|
+
|
|
90
|
+
// JWT exp is in seconds, Date.now() is in milliseconds
|
|
91
|
+
const now = Math.floor(Date.now() / 1000);
|
|
92
|
+
return decoded.exp > now;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
app,
|
|
97
|
+
auth,
|
|
98
|
+
db,
|
|
99
|
+
tokenStore,
|
|
100
|
+
decodeToken,
|
|
101
|
+
getCurrentUserUid,
|
|
102
|
+
getCurrentUserEmail,
|
|
103
|
+
isTokenValid
|
|
104
|
+
};
|