kalvium-worklog 1.4.0 → 1.4.1

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,5 +1,7 @@
1
1
  /**
2
- * Discover the user's internship position ID by capturing API calls.
3
- * Tries headless first, falls back to headed browser for manual login.
2
+ * Discover the user's internship position ID.
3
+ * Tries JWT extraction first (no browser needed).
4
+ * Falls back to browser-based discovery via Playwright if available.
5
+ * On Android, uses JWT extraction only.
4
6
  */
5
7
  export declare function discoverPosition(): Promise<boolean>;
@@ -1,31 +1,71 @@
1
- import { chromium } from "playwright";
2
- import { PROFILE_DIR, CONFIG_FILE, ensureInstallDir, saveConfig, } from "./config.js";
1
+ import { PROFILE_DIR, CONFIG_FILE, ensureInstallDir, saveConfig, loadToken, getPositionIdFromToken, } from "./config.js";
3
2
  /**
4
- * Discover the user's internship position ID by capturing API calls.
5
- * Tries headless first, falls back to headed browser for manual login.
3
+ * Check if Playwright is available on this platform.
4
+ */
5
+ function isPlaywrightAvailable() {
6
+ try {
7
+ if (process.platform === "android")
8
+ return false;
9
+ require.resolve("playwright");
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ /**
17
+ * Discover the user's internship position ID.
18
+ * Tries JWT extraction first (no browser needed).
19
+ * Falls back to browser-based discovery via Playwright if available.
20
+ * On Android, uses JWT extraction only.
6
21
  */
7
22
  export async function discoverPosition() {
8
23
  ensureInstallDir();
9
24
  console.log("=== Discovering internship position ID ===\n");
10
- // Step 1: Try headless first
11
- console.log("1. Trying headless mode (existing session)...");
12
- let captured = await discoverViaBrowser(true);
25
+ // Step 1: Try extracting from saved token (no browser needed)
26
+ const token = loadToken();
27
+ if (token) {
28
+ const positionId = getPositionIdFromToken(token);
29
+ if (positionId) {
30
+ const worklogUrl = `https://student-api.kalvium.community/api/internships/worklogs/${positionId}`;
31
+ saveConfig({ position_id: positionId, worklog_api_url: worklogUrl });
32
+ console.log(`\n=== SUCCESS ===`);
33
+ console.log(`Position ID: ${positionId}`);
34
+ console.log(`Worklog API: ${worklogUrl}`);
35
+ console.log(`Saved to: ${CONFIG_FILE}`);
36
+ return true;
37
+ }
38
+ console.log(" Could not extract position ID from token.");
39
+ }
40
+ else {
41
+ console.log(" No token found. Run `kalvium-worklog login` first.");
42
+ }
43
+ // Step 2: Fall back to browser-based discovery (if Playwright available)
44
+ if (!isPlaywrightAvailable()) {
45
+ console.log("\nERROR: Could not discover position ID.");
46
+ console.log("Playwright is not available on this platform.");
47
+ console.log("Make sure you have a valid token (run `kalvium-worklog login`).");
48
+ return false;
49
+ }
50
+ const { chromium } = await import("playwright");
51
+ console.log("\n1. Trying headless mode (existing session)...");
52
+ let captured = await discoverViaBrowser(chromium, true);
13
53
  if (!captured.token) {
14
54
  console.log(" No valid session. Opening browser for manual login...");
15
- captured = await discoverViaBrowser(false);
55
+ captured = await discoverViaBrowser(chromium, false);
16
56
  }
17
57
  if (!captured.token) {
18
58
  console.log("\nERROR: Could not capture token. Please log in and try again.");
19
59
  return false;
20
60
  }
21
61
  console.log(` Token captured: ${captured.token.slice(0, 40)}...`);
22
- // Step 2: Extract position ID from captured API URLs
62
+ // Step 3: Extract position ID from captured API URLs
23
63
  const positionId = extractPositionId(captured.api_url ?? "");
24
64
  if (!positionId) {
25
65
  console.log("\nERROR: Could not determine position ID from API calls");
26
66
  return false;
27
67
  }
28
- // Step 3: Save config
68
+ // Step 4: Save config
29
69
  const worklogUrl = `https://student-api.kalvium.community/api/internships/worklogs/${positionId}`;
30
70
  saveConfig({ position_id: positionId, worklog_api_url: worklogUrl });
31
71
  console.log(`\n=== SUCCESS ===`);
@@ -34,7 +74,7 @@ export async function discoverPosition() {
34
74
  console.log(`Saved to: ${CONFIG_FILE}`);
35
75
  return true;
36
76
  }
37
- async function discoverViaBrowser(headless) {
77
+ async function discoverViaBrowser(chromium, headless) {
38
78
  const captured = {};
39
79
  const context = await chromium.launchPersistentContext(PROFILE_DIR, {
40
80
  headless: false,
@@ -75,16 +115,25 @@ async function discoverViaBrowser(headless) {
75
115
  }
76
116
  else {
77
117
  console.log("\n ========================================");
78
- console.log(" Browser opened. Please log in now:");
79
- console.log(" 1. Click 'Continue with Google'");
80
- console.log(" 2. Sign in with your Kalvium account");
81
- console.log(" 3. Complete 2FA if prompted");
82
- console.log(" 4. Wait — the script continues automatically");
118
+ console.log(" Browser opened. Auto-clicking 'Continue with Google'...");
119
+ console.log(" Please complete 2FA if prompted.");
83
120
  console.log(" ========================================\n");
84
121
  await page.goto("https://kalvium.community/internships", {
85
122
  waitUntil: "domcontentloaded",
86
123
  timeout: 120000,
87
124
  });
125
+ // Auto-click "Continue with Google"
126
+ try {
127
+ const googleBtn = page.locator("text=Continue with Google").first();
128
+ const isVisible = await googleBtn.isVisible().catch(() => false);
129
+ if (isVisible) {
130
+ await googleBtn.click();
131
+ console.log(" Clicked 'Continue with Google'.");
132
+ }
133
+ }
134
+ catch {
135
+ // ignore
136
+ }
88
137
  console.log(" Waiting for login to complete (up to 5 minutes)...");
89
138
  for (let i = 0; i < 300; i++) {
90
139
  if (captured.token && captured.api_url)
@@ -112,7 +161,6 @@ function extractPositionId(apiUrl) {
112
161
  if (internshipsIdx === -1)
113
162
  return null;
114
163
  for (const part of parts.slice(internshipsIdx + 1)) {
115
- // Position IDs are UUIDs (36 chars, 4 dashes)
116
164
  if (part.length === 36 && part.split("-").length === 5) {
117
165
  return part;
118
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kalvium-worklog",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Auto-submit your daily Kalvium worklog without opening the website",
5
5
  "keywords": [
6
6
  "kalvium",