pi-antigravity-rotator 2.3.1 → 2.3.2
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/CHANGELOG.md +20 -0
- package/README.md +17 -11
- package/package.json +11 -7
- package/src/cli.ts +27 -2
- package/src/compat/translators.ts +58 -8
- package/src/compat.ts +103 -15
- package/src/exposure.ts +17 -0
- package/src/index.ts +12 -0
- package/src/login.ts +4 -3
- package/src/notification-poller.ts +23 -10
- package/src/onboarding.ts +16 -1
- package/src/proxy.ts +398 -392
- package/src/rotator.ts +10 -6
- package/src/static/dashboard.js +7 -2
- package/src/telemetry.ts +7 -5
- package/src/types.ts +2 -9
- package/src/version-check.ts +23 -10
- package/tools/telemetry-receiver/README.md +2 -1
package/src/login.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { createInterface } from "node:readline";
|
|
8
8
|
import { addAccountToConfig, ensurePiAuthConfig, ensurePiModelsConfig, loadOrCreateAccountsConfig } from "./account-store.js";
|
|
9
|
-
import { buildAuthUrl, discoverProject, exchangeAuthorizationCode, generatePkce, getOAuthClientConfig, getUserEmail } from "./oauth.js";
|
|
9
|
+
import { buildAuthUrl, discoverProject, exchangeAuthorizationCode, generatePkce, generateState, getOAuthClientConfig, getUserEmail } from "./oauth.js";
|
|
10
10
|
import type { AccountConfig } from "./types.js";
|
|
11
11
|
import { getAccountsPath } from "./paths.js";
|
|
12
12
|
|
|
@@ -42,7 +42,8 @@ export async function runLogin(): Promise<void> {
|
|
|
42
42
|
|
|
43
43
|
const oauth = getOAuthClientConfig();
|
|
44
44
|
const { verifier, challenge } = generatePkce();
|
|
45
|
-
const
|
|
45
|
+
const state = generateState();
|
|
46
|
+
const authUrl = buildAuthUrl(state, challenge);
|
|
46
47
|
|
|
47
48
|
console.log("1. Open this URL in your browser:");
|
|
48
49
|
console.log();
|
|
@@ -66,7 +67,7 @@ export async function runLogin(): Promise<void> {
|
|
|
66
67
|
process.exit(1);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
if (parsed.state
|
|
70
|
+
if (parsed.state !== state) {
|
|
70
71
|
console.error("State mismatch - the URL does not match this login session.");
|
|
71
72
|
process.exit(1);
|
|
72
73
|
}
|
|
@@ -48,6 +48,7 @@ function getVersion(): string {
|
|
|
48
48
|
|
|
49
49
|
// ── Cached notifications ─────────────────────────────────────────────
|
|
50
50
|
let _notifications: AdminNotification[] = [];
|
|
51
|
+
let _initialPollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
51
52
|
let _pollTimer: ReturnType<typeof setInterval> | null = null;
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -100,18 +101,26 @@ export function startNotificationPoller(): void {
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
// Initial delayed fetch
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
if (!_initialPollTimer) {
|
|
105
|
+
_initialPollTimer = setTimeout(() => {
|
|
106
|
+
_initialPollTimer = null;
|
|
107
|
+
void fetchNotifications();
|
|
108
|
+
}, 15_000);
|
|
109
|
+
if (_initialPollTimer.unref) {
|
|
110
|
+
_initialPollTimer.unref();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
106
113
|
|
|
107
114
|
// Periodic poll
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
_pollTimer.unref
|
|
115
|
+
if (!_pollTimer) {
|
|
116
|
+
_pollTimer = setInterval(() => {
|
|
117
|
+
void fetchNotifications();
|
|
118
|
+
}, POLL_INTERVAL_MS);
|
|
119
|
+
|
|
120
|
+
// Don't prevent process exit
|
|
121
|
+
if (_pollTimer.unref) {
|
|
122
|
+
_pollTimer.unref();
|
|
123
|
+
}
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
|
|
@@ -119,6 +128,10 @@ export function startNotificationPoller(): void {
|
|
|
119
128
|
* Stop notification polling.
|
|
120
129
|
*/
|
|
121
130
|
export function stopNotificationPoller(): void {
|
|
131
|
+
if (_initialPollTimer) {
|
|
132
|
+
clearTimeout(_initialPollTimer);
|
|
133
|
+
_initialPollTimer = null;
|
|
134
|
+
}
|
|
122
135
|
if (_pollTimer) {
|
|
123
136
|
clearInterval(_pollTimer);
|
|
124
137
|
_pollTimer = null;
|
package/src/onboarding.ts
CHANGED
|
@@ -203,6 +203,7 @@ export function startHostedLogin(
|
|
|
203
203
|
interface CliLoginSession {
|
|
204
204
|
verifier: string;
|
|
205
205
|
challenge: string;
|
|
206
|
+
oauthState: string;
|
|
206
207
|
authUrl: string;
|
|
207
208
|
createdAt: number;
|
|
208
209
|
}
|
|
@@ -221,11 +222,13 @@ function pruneCliSessions(): void {
|
|
|
221
222
|
export function serveCliLogin(res: ServerResponse): void {
|
|
222
223
|
pruneCliSessions();
|
|
223
224
|
const { verifier, challenge } = generatePkce();
|
|
224
|
-
const
|
|
225
|
+
const oauthState = generateState();
|
|
226
|
+
const authUrl = buildAuthUrl(oauthState, challenge);
|
|
225
227
|
const sessionId = generateState();
|
|
226
228
|
cliLoginSessions.set(sessionId, {
|
|
227
229
|
verifier,
|
|
228
230
|
challenge,
|
|
231
|
+
oauthState,
|
|
229
232
|
authUrl,
|
|
230
233
|
createdAt: Date.now(),
|
|
231
234
|
});
|
|
@@ -348,9 +351,11 @@ export async function handleCliLoginApi(
|
|
|
348
351
|
|
|
349
352
|
// Parse the redirect URL to extract code
|
|
350
353
|
let code: string | undefined;
|
|
354
|
+
let state: string | null;
|
|
351
355
|
try {
|
|
352
356
|
const url = new URL(redirectUrl.trim());
|
|
353
357
|
code = url.searchParams.get("code") ?? undefined;
|
|
358
|
+
state = url.searchParams.get("state");
|
|
354
359
|
} catch {
|
|
355
360
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
356
361
|
res.end(
|
|
@@ -373,6 +378,16 @@ export async function handleCliLoginApi(
|
|
|
373
378
|
);
|
|
374
379
|
return;
|
|
375
380
|
}
|
|
381
|
+
if (state !== session.oauthState) {
|
|
382
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
383
|
+
res.end(
|
|
384
|
+
JSON.stringify({
|
|
385
|
+
ok: false,
|
|
386
|
+
error: "State mismatch - reload the login page and try again.",
|
|
387
|
+
}),
|
|
388
|
+
);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
376
391
|
|
|
377
392
|
cliLoginSessions.delete(sessionId);
|
|
378
393
|
|