kalvium-worklog 1.4.3 → 1.4.5

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Try headless mode first (fast — works if session is still valid).
3
3
  * If no session, opens a headed browser and waits for manual login.
4
- * On platforms without Playwright (e.g. Android/Termux), uses the
5
- * phone's built-in browser + a local HTTP server to capture the token.
4
+ * On platforms without Playwright (e.g. Android/Termux), uses a
5
+ * reverse proxy to capture the token automatically.
6
6
  */
7
7
  export declare function captureToken(): Promise<boolean>;
@@ -1,7 +1,5 @@
1
1
  import { PROFILE_DIR, TOKEN_FILE, ensureInstallDir, saveToken, } from "./config.js";
2
2
  import * as readline from "readline";
3
- import { createServer } from "http";
4
- import { execSync } from "child_process";
5
3
  /**
6
4
  * Check if Playwright is available on this platform.
7
5
  * Playwright doesn't support Android/Termux.
@@ -20,24 +18,21 @@ function isPlaywrightAvailable() {
20
18
  /**
21
19
  * Try headless mode first (fast — works if session is still valid).
22
20
  * If no session, opens a headed browser and waits for manual login.
23
- * On platforms without Playwright (e.g. Android/Termux), uses the
24
- * phone's built-in browser + a local HTTP server to capture the token.
21
+ * On platforms without Playwright (e.g. Android/Termux), uses a
22
+ * reverse proxy to capture the token automatically.
25
23
  */
26
24
  export async function captureToken() {
27
25
  ensureInstallDir();
28
26
  if (!isPlaywrightAvailable()) {
29
- return captureTokenViaBrowser();
27
+ return captureTokenViaProxy();
30
28
  }
31
- // Lazy import — only load Playwright when available
32
29
  const { chromium } = await import("playwright");
33
- // Step 1: Try headless (quick — works if session is still valid)
34
30
  console.log("Trying headless mode (existing session)...");
35
31
  let data = await tryCapture(chromium, true);
36
32
  if (data) {
37
33
  console.log(" Session still valid — token captured!");
38
34
  }
39
35
  else {
40
- // Step 2: Need manual login
41
36
  console.log(" No valid session. Opening browser for manual login...");
42
37
  data = await tryCapture(chromium, false);
43
38
  }
@@ -53,184 +48,31 @@ export async function captureToken() {
53
48
  }
54
49
  /**
55
50
  * Capture token on platforms without Playwright (Android/Termux).
56
- * Starts a local HTTP server, opens the phone's browser to kalvium.community,
57
- * and after login the user pastes a JS snippet that sends the token back.
51
+ * Simple manual paste user gets token from desktop and pastes it.
58
52
  */
59
- async function captureTokenViaBrowser() {
60
- const PORT = 4567;
53
+ async function captureTokenViaProxy() {
61
54
  console.log("\n ========================================");
62
- console.log(" Browser-based token capture (no Playwright)");
55
+ console.log(" Token Setup (Android/Termux)");
63
56
  console.log(" ========================================\n");
64
- // Start local HTTP server
65
- const tokenPromise = new Promise((resolve) => {
66
- const server = createServer((req, res) => {
67
- res.setHeader("Access-Control-Allow-Origin", "*");
68
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
69
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
70
- if (req.method === "OPTIONS") {
71
- res.writeHead(204);
72
- res.end();
73
- return;
74
- }
75
- let body = "";
76
- req.on("data", (chunk) => {
77
- body += chunk;
78
- });
79
- req.on("end", () => {
80
- // Token capture endpoint
81
- if (req.url?.startsWith("/capture")) {
82
- try {
83
- let data;
84
- if (body) {
85
- data = JSON.parse(body);
86
- }
87
- else {
88
- const url = new URL(req.url, `http://localhost:${PORT}`);
89
- const tokenParam = url.searchParams.get("token");
90
- if (!tokenParam) {
91
- res.writeHead(400);
92
- res.end("Missing token");
93
- return;
94
- }
95
- data = JSON.parse(tokenParam);
96
- }
97
- if (data.refresh_token) {
98
- res.writeHead(200, { "Content-Type": "text/html" });
99
- res.end("<html><body style='font-family:sans-serif;text-align:center;padding:40px'><h2>✓ Token captured!</h2><p>You can close this tab and go back to Termux.</p></body></html>");
100
- resolve(data);
101
- }
102
- else {
103
- res.writeHead(400, { "Content-Type": "text/html" });
104
- res.end("<html><body><h2>Invalid token — missing refresh_token</h2></body></html>");
105
- resolve(null);
106
- }
107
- }
108
- catch {
109
- res.writeHead(400, { "Content-Type": "text/html" });
110
- res.end("<html><body><h2>Invalid JSON</h2></body></html>");
111
- resolve(null);
112
- }
113
- return;
114
- }
115
- // Main page — serves instructions + manual paste form
116
- res.writeHead(200, { "Content-Type": "text/html" });
117
- res.end(`<!DOCTYPE html>
118
- <html>
119
- <head>
120
- <meta name="viewport" content="width=device-width, initial-scale=1">
121
- <title>Kalvium Worklog — Login</title>
122
- <style>
123
- * { box-sizing: border-box; }
124
- body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 16px; line-height: 1.6; color: #333; }
125
- h2 { color: #1a73e8; }
126
- .step { background: #f0f4ff; border-radius: 12px; padding: 16px; margin: 12px 0; }
127
- .step h3 { margin-top: 0; color: #1a73e8; }
128
- .btn { display: block; text-align: center; background: #4285f4; color: white; padding: 14px; border-radius: 8px; text-decoration: none; font-size: 18px; font-weight: bold; margin: 12px 0; }
129
- .btn-green { background: #34a853; }
130
- .btn:active { opacity: 0.8; }
131
- .code-box { background: #1e1e1e; color: #0f0; padding: 12px; border-radius: 8px; font-family: monospace; font-size: 12px; word-break: break-all; white-space: pre-wrap; user-select: all; }
132
- .note { background: #fff8e1; border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 14px; }
133
- .warn { background: #fce4ec; border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 14px; }
134
- textarea { width: 100%; height: 120px; font-family: monospace; font-size: 12px; border: 2px solid #4285f4; border-radius: 8px; padding: 8px; }
135
- #result { font-weight: bold; padding: 12px; border-radius: 8px; margin: 8px 0; display: none; }
136
- .success { background: #e8f5e9; color: #2e7d32; }
137
- .error { background: #ffebee; color: #c62828; }
138
- </style>
139
- </head>
140
- <body>
141
- <h2>Kalvium Worklog — Login</h2>
142
-
143
- <div class="step">
144
- <h3>Step 1: Log in to Kalvium</h3>
145
- <p>Tap below, log in with Google (2FA if asked).</p>
146
- <a class="btn btn-green" href="https://kalvium.community/internships" target="_blank">Open Kalvium →</a>
147
- </div>
148
-
149
- <div class="step">
150
- <h3>Step 2: Extract token</h3>
151
- <p>After logging in, go to the Kalvium tab.<br>
152
- <b>Type</b> this in the address bar (don't paste — type <code>javascript:</code> yourself, then paste the rest):</p>
153
- <div class="code-box" id="jscode">javascript:void(function(){var t;for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i),v=localStorage.getItem(i);if(v&&v.includes('refresh_token')){t=v}}if(!t){for(var i=0;i<sessionStorage.length;i++){var k=sessionStorage.key(i),v=sessionStorage.getItem(i);if(v&&v.includes('refresh_token')){t=v}}}if(t){fetch('http://localhost:${PORT}/capture',{method:'POST',body:t}).then(function(r){alert(r.ok?'Token sent! Go back to Termux':'Failed: '+r.status)}).catch(function(e){alert('Error: '+e)})}else{alert('No token found. Are you logged in?')}})()</div>
154
- <p><small>👆 Long-press the code above → "Copy", then go to Kalvium tab, type <code>javascript:</code> in address bar, paste the rest after it, press Enter.</small></p>
155
- </div>
156
-
157
- <div class="warn">
158
- <b>Brave users:</b> Brave strips <code>javascript:</code> when pasting. You must <b>type</b> <code>javascript:</code> manually, then paste only the code after <code>javascript:</code>.
159
- </div>
160
-
161
- <div class="step">
162
- <h3>Or: Paste token manually</h3>
163
- <p>If the above doesn't work, extract the token another way and paste it here:</p>
164
- <textarea id="manualToken" placeholder='Paste token JSON here (starts with {"access_token"...'></textarea>
165
- <button class="btn" onclick="sendManual()">Send Token</button>
166
- <div id="result"></div>
167
- </div>
168
-
169
- <script>
170
- function sendManual() {
171
- var val = document.getElementById('manualToken').value.trim();
172
- var result = document.getElementById('result');
173
- result.style.display = 'block';
174
- if (!val) { result.className = 'error'; result.textContent = 'Paste token JSON first'; return; }
175
- fetch('http://localhost:${PORT}/capture', { method: 'POST', body: val })
176
- .then(function(r) {
177
- if (r.ok) { result.className = 'success'; result.textContent = '✓ Token sent! Go back to Termux.'; }
178
- else { result.className = 'error'; result.textContent = 'Failed: ' + r.status; }
179
- })
180
- .catch(function(e) { result.className = 'error'; result.textContent = 'Error: ' + e; });
181
- }
182
- </script>
183
-
184
- </body>
185
- </html>`);
186
- });
187
- });
188
- server.listen(PORT, () => {
189
- console.log(` Local server running on http://localhost:${PORT}`);
190
- });
191
- setTimeout(() => {
192
- server.close();
193
- resolve(null);
194
- }, 300000);
195
- });
196
- // Open the localhost page in the browser
197
- const localUrl = `http://localhost:${PORT}`;
198
- try {
199
- if (process.platform === "android") {
200
- execSync(`termux-open-url ${localUrl}`, { stdio: "ignore" });
201
- }
202
- else {
203
- execSync(`xdg-open ${localUrl} || open ${localUrl}`, {
204
- stdio: "ignore",
205
- });
206
- }
207
- console.log(` Opened ${localUrl} in your browser.`);
208
- }
209
- catch {
210
- console.log(` Could not auto-open browser. Please open: ${localUrl}`);
211
- }
212
- console.log("\n ────────────────────────────────────────────");
213
- console.log(" A page opened in your browser with instructions:");
214
- console.log(" 1. Click 'Open Kalvium' and log in");
215
- console.log(" 2. Long-press 'Capture Token' → Bookmark it");
216
- console.log(" 3. Go to Kalvium tab → open the bookmark");
57
+ console.log(" Playwright doesn't work on Android, so you");
58
+ console.log(" need to get your token from a desktop.\n");
217
59
  console.log(" ────────────────────────────────────────────");
218
- console.log("\n Waiting for token (up to 5 minutes)...\n");
219
- const data = await tokenPromise;
220
- if (data) {
221
- saveToken(data);
222
- console.log(`\n✓ Token captured and saved to ${TOKEN_FILE}`);
223
- console.log(` Access token expires in: ${data.expires_in ?? "?"} seconds`);
224
- console.log(` Refresh token expires in: ${data.refresh_expires_in ?? "?"} seconds`);
225
- return true;
226
- }
227
- // Fallback: manual paste
228
- console.log("\n Automatic capture failed. Let's try manual paste.");
60
+ console.log(" ON YOUR DESKTOP/LAPTOP:");
61
+ console.log(" ────────────────────────────────────────────");
62
+ console.log(" 1. Install: npm install -g kalvium-worklog");
63
+ console.log(" 2. Run: kalvium-worklog login");
64
+ console.log(" 3. Log in with Google");
65
+ console.log(" 4. Run: cat ~/.kalvium/refresh_token.json");
66
+ console.log(" 5. Copy the entire JSON output\n");
67
+ console.log(" ────────────────────────────────────────────");
68
+ console.log(" THEN ON YOUR PHONE:");
69
+ console.log(" ────────────────────────────────────────────");
70
+ console.log(" 6. Paste the JSON below\n");
229
71
  return captureTokenManual();
230
72
  }
231
73
  /**
232
- * Manual token capture — fallback for platforms without Playwright.
233
- * Prompts the user to paste a refresh token JSON obtained from a desktop.
74
+ * Manual token capture — fallback.
75
+ * Prompts the user to paste a refresh token JSON.
234
76
  */
235
77
  async function captureTokenManual() {
236
78
  console.log("\n ========================================");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kalvium-worklog",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "Auto-submit your daily Kalvium worklog without opening the website",
5
5
  "keywords": [
6
6
  "kalvium",