omnibiofex 2.8.5 → 4.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/obx +30 -158
- package/package.json +13 -28
- package/src/auth.js +181 -381
- package/src/commands/account.js +35 -88
- package/src/commands/data.js +40 -114
- package/src/commands/debug.js +28 -25
- package/src/commands/earnings.js +31 -86
- package/src/commands/mission.js +194 -98
- package/src/commands/morning.js +39 -107
- package/src/commands/open.js +26 -36
- package/src/commands/publish.js +81 -126
- package/src/commands/research.js +148 -281
- package/src/commands/timeline.js +15 -54
- package/src/firebase.js +4 -14
- package/src/user.js +94 -0
- package/src/utils/display.js +27 -856
- package/src/api.js +0 -72
- package/src/config.js +0 -16
package/src/commands/publish.js
CHANGED
|
@@ -1,165 +1,120 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('inquirer');
|
|
3
|
-
const { getAuthToken, isAuthenticated
|
|
4
|
-
const { db } = require('../firebase');
|
|
3
|
+
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
5
4
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
6
|
-
const { collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
6
|
+
const GET_USER_DATA_URL = 'https://getuserdata-yyedhmslhq-uc.a.run.app';
|
|
7
|
+
const PUBLISH_MISSION_URL = 'https://publishmission-yyedhmslhq-uc.a.run.app';
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
9
|
+
async function fetchUserData(token) {
|
|
10
|
+
const response = await fetch(GET_USER_DATA_URL, {
|
|
11
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) throw new Error(`Backend error: ${response.status}`);
|
|
14
|
+
return await response.json();
|
|
15
|
+
}
|
|
22
16
|
|
|
17
|
+
async function publish(missionId) {
|
|
18
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
19
|
+
|
|
23
20
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
24
21
|
console.log(chalk.white.bold('📤 PUBLISH RESEARCH'));
|
|
25
22
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
26
|
-
|
|
27
|
-
console.log(chalk.gray(` 👤 User: ${chalk.white(email || 'Unknown')}`));
|
|
28
|
-
|
|
29
|
-
if (!missionId) {
|
|
30
|
-
console.log(chalk.gray('\nFetching your completed missions...\n'));
|
|
31
|
-
|
|
32
|
-
const spinner = new PremiumSpinner('Loading missions from database');
|
|
33
|
-
spinner.start();
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
collection(db, 'missions'),
|
|
38
|
-
where('uid', '==', uid),
|
|
39
|
-
where('status', '==', 'completed'),
|
|
40
|
-
where('isPublished', '==', false),
|
|
41
|
-
orderBy('createdAt', 'desc'),
|
|
42
|
-
limit(10)
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const querySnapshot = await getDocs(missionsQuery);
|
|
46
|
-
const missions = [];
|
|
47
|
-
|
|
48
|
-
querySnapshot.forEach((docSnap) => {
|
|
49
|
-
missions.push({
|
|
50
|
-
id: docSnap.id,
|
|
51
|
-
...docSnap.data()
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
spinner.succeed(`Found ${missions.length} unpublished missions`);
|
|
24
|
+
const spinner = new PremiumSpinner('Fetching missions');
|
|
25
|
+
spinner.start();
|
|
56
26
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
try {
|
|
28
|
+
const token = await getAuthToken();
|
|
29
|
+
const userData = await fetchUserData(token);
|
|
30
|
+
spinner.succeed('Missions loaded');
|
|
31
|
+
|
|
32
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(userData.user.name || userData.user.email)}`));
|
|
33
|
+
|
|
34
|
+
// Filter unpublished completed missions
|
|
35
|
+
const unpublished = userData.missions.filter(m =>
|
|
36
|
+
m.status === 'completed' && !m.isPublished
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (!missionId) {
|
|
40
|
+
if (unpublished.length === 0) {
|
|
41
|
+
console.log(chalk.yellow('\n⚠️ No unpublished missions.\n'));
|
|
42
|
+
console.log(chalk.gray(' Create one with: obx mission create\n'));
|
|
43
|
+
process.exit(0);
|
|
60
44
|
return;
|
|
61
45
|
}
|
|
62
|
-
|
|
63
|
-
console.log(chalk.white('\n📋
|
|
46
|
+
|
|
47
|
+
console.log(chalk.white('\n📋 Unpublished Missions:'));
|
|
64
48
|
console.log(chalk.gray('─'.repeat(60)));
|
|
65
49
|
|
|
66
|
-
|
|
67
|
-
const date = m.createdAt?.toDate?.().toLocaleDateString() || 'N/A';
|
|
50
|
+
unpublished.forEach((m, i) => {
|
|
68
51
|
console.log(chalk.white(`\n${i + 1}. ${chalk.hex('#F24E1E')(m.id)}`));
|
|
69
|
-
console.log(chalk.white(` Topic: ${(m.message || '
|
|
70
|
-
console.log(chalk.green(` Type: ${m.taskType || 'Research'}`));
|
|
71
|
-
console.log(chalk.gray(` Date: ${date}`));
|
|
72
|
-
console.log(chalk.gray(` RCC Cost: ${m.rccCost || 0}`));
|
|
52
|
+
console.log(chalk.white(` Topic: ${(m.message || '').substring(0, 60)}`));
|
|
73
53
|
});
|
|
74
|
-
|
|
75
|
-
const { selectedIndex } = await inquirer.prompt([
|
|
76
|
-
{
|
|
77
|
-
type: 'list',
|
|
78
|
-
name: 'selectedIndex',
|
|
79
|
-
message: '\nSelect mission to publish:',
|
|
80
|
-
choices: missions.map((m, i) => ({
|
|
81
|
-
name: `${i + 1}. ${m.id} - ${(m.message || 'No topic').substring(0, 50)}`,
|
|
82
|
-
value: i
|
|
83
|
-
}))
|
|
84
|
-
}
|
|
85
|
-
]);
|
|
86
|
-
|
|
87
|
-
missionId = missions[selectedIndex].id;
|
|
88
54
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
55
|
+
const { selectedIndex } = await inquirer.prompt([{
|
|
56
|
+
type: 'list', name: 'selectedIndex', message: '\nSelect mission:',
|
|
57
|
+
choices: unpublished.map((m, i) => ({
|
|
58
|
+
name: `${i + 1}. ${m.id} - ${(m.message || '').substring(0, 50)}`,
|
|
59
|
+
value: i
|
|
60
|
+
}))
|
|
61
|
+
}]);
|
|
62
|
+
missionId = unpublished[selectedIndex].id;
|
|
93
63
|
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const spinner = new PremiumSpinner('Preparing to publish research');
|
|
97
|
-
spinner.start();
|
|
98
|
-
await sleep(500);
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
spinner.update('Fetching mission data');
|
|
102
|
-
const missionRef = doc(db, 'missions', missionId);
|
|
103
|
-
|
|
104
|
-
const missionSnap = await getDocs(query(collection(db, 'missions'), where('__name__', '==', missionId)));
|
|
105
|
-
|
|
106
|
-
if (missionSnap.empty) {
|
|
107
|
-
spinner.fail('Mission not found');
|
|
108
|
-
console.error(chalk.red(`✗ Mission ${missionId} not found`));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const missionData = missionSnap.docs[0].data();
|
|
113
64
|
|
|
114
|
-
|
|
65
|
+
const publishSpinner = new PremiumSpinner('Publishing research');
|
|
66
|
+
publishSpinner.start();
|
|
115
67
|
await sleep(500);
|
|
116
68
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
.replace(/^-|-$/g, '')
|
|
121
|
-
.substring(0, 60) + '-' + Date.now().toString(36);
|
|
122
|
-
|
|
123
|
-
spinner.update('Adding metadata and tags');
|
|
69
|
+
publishSpinner.update('Generating SEO page');
|
|
70
|
+
await sleep(500);
|
|
71
|
+
publishSpinner.update('Adding metadata');
|
|
124
72
|
await sleep(400);
|
|
125
|
-
|
|
126
|
-
spinner.update('Submitting to Google for indexing');
|
|
73
|
+
publishSpinner.update('Submitting to Google');
|
|
127
74
|
await sleep(600);
|
|
128
|
-
|
|
129
|
-
spinner.update('Enabling revenue tracking');
|
|
75
|
+
publishSpinner.update('Enabling revenue tracking');
|
|
130
76
|
await sleep(400);
|
|
131
77
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
authorName: email || 'Anonymous Researcher',
|
|
141
|
-
authorEmail: email || 'unknown@example.com'
|
|
78
|
+
// Call backend to publish
|
|
79
|
+
const response = await fetch(PUBLISH_MISSION_URL, {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: {
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
'Authorization': `Bearer ${token}`
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify({ missionId })
|
|
142
86
|
});
|
|
143
87
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const err = await response.json().catch(() => ({ error: `HTTP ${response.status}` }));
|
|
90
|
+
throw new Error(err.error || `Backend returned ${response.status}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
publishSpinner.succeed('Research published successfully!');
|
|
95
|
+
|
|
148
96
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
149
97
|
console.log(chalk.white.bold('✅ PUBLICATION DETAILS'));
|
|
150
98
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
151
|
-
|
|
152
99
|
console.log(chalk.white(`📄 Mission ID: ${chalk.hex('#F24E1E')(missionId)}`));
|
|
153
|
-
console.log(chalk.white(`🔗 Public URL: ${chalk.blue.underline(url)}`));
|
|
100
|
+
console.log(chalk.white(`🔗 Public URL: ${chalk.blue.underline(data.url)}`));
|
|
154
101
|
console.log(chalk.white(`💰 Revenue Share: ${chalk.green('80%')} of all ad revenue`));
|
|
155
102
|
console.log(chalk.white(`🔍 Google Indexing: ${chalk.green('Requested')} (24 hours)`));
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
console.log(chalk.
|
|
159
|
-
|
|
103
|
+
|
|
104
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
105
|
+
console.log(chalk.white.bold('💰 START EARNING'));
|
|
106
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
107
|
+
console.log(chalk.white('\n ✓ Google indexes within 24 hours'));
|
|
108
|
+
console.log(chalk.white(' ✓ Readers discover through search'));
|
|
109
|
+
console.log(chalk.white(' ✓ You earn 80% of ad revenue'));
|
|
110
|
+
console.log(chalk.white(' ✓ Monthly payouts to your account\n'));
|
|
111
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
112
|
+
process.exit(0);
|
|
113
|
+
|
|
160
114
|
} catch (error) {
|
|
161
|
-
spinner.fail('Failed to publish
|
|
115
|
+
spinner.fail('Failed to publish');
|
|
162
116
|
console.error(chalk.red(error.message));
|
|
117
|
+
process.exit(1);
|
|
163
118
|
}
|
|
164
119
|
}
|
|
165
120
|
|