@kenkaiiii/gg-core 5.39.3 → 5.40.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/dist/{chunk-XDE6VUI4.js → chunk-JH7OVHH5.js} +89 -31
- package/dist/chunk-JH7OVHH5.js.map +1 -0
- package/dist/index.cjs +88 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +1 -1
- package/dist/model-registry.cjs +1 -0
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-XDE6VUI4.js.map +0 -1
|
@@ -256,6 +256,7 @@ import path2 from "path";
|
|
|
256
256
|
import { randomBytes } from "crypto";
|
|
257
257
|
import { environmentSecrets, redactText, redactValue } from "@kenkaiiii/gg-ai";
|
|
258
258
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
259
|
+
var MIN_HEADROOM_BYTES = 64 * 1024;
|
|
259
260
|
var fd = null;
|
|
260
261
|
var bytesWritten = 0;
|
|
261
262
|
var capped = false;
|
|
@@ -266,7 +267,7 @@ var exactSecrets = [];
|
|
|
266
267
|
function rotateIfNeeded(filePath) {
|
|
267
268
|
try {
|
|
268
269
|
const st = fs.statSync(filePath);
|
|
269
|
-
if (st.size
|
|
270
|
+
if (st.size <= MAX_BYTES - MIN_HEADROOM_BYTES) return;
|
|
270
271
|
const rotated = `${filePath}.1`;
|
|
271
272
|
try {
|
|
272
273
|
fs.unlinkSync(rotated);
|
|
@@ -561,6 +562,9 @@ var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
|
561
562
|
var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
|
|
562
563
|
var SCOPE = "openid profile email offline_access api.connectors.read api.connectors.invoke";
|
|
563
564
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
565
|
+
var CALLBACK_TIMEOUT_MS = 12e4;
|
|
566
|
+
var MAX_PASTE_ATTEMPTS = 3;
|
|
567
|
+
var MIN_RAW_CODE_LENGTH = 10;
|
|
564
568
|
async function loginOpenAI(callbacks) {
|
|
565
569
|
const { verifier, challenge } = await generatePKCE();
|
|
566
570
|
const state = crypto3.randomBytes(16).toString("hex");
|
|
@@ -576,20 +580,7 @@ async function loginOpenAI(callbacks) {
|
|
|
576
580
|
url.searchParams.set("id_token_add_organizations", "true");
|
|
577
581
|
url.searchParams.set("codex_cli_simplified_flow", "true");
|
|
578
582
|
url.searchParams.set("originator", "ggcoder");
|
|
579
|
-
|
|
580
|
-
try {
|
|
581
|
-
code = await loginWithServer(url.toString(), state, callbacks);
|
|
582
|
-
} catch {
|
|
583
|
-
callbacks.onOpenUrl(url.toString());
|
|
584
|
-
const raw = await callbacks.onPromptCode(
|
|
585
|
-
"Could not start local server. Paste the callback URL or code from the browser:"
|
|
586
|
-
);
|
|
587
|
-
const parsed = parseAuthorizationInput(raw);
|
|
588
|
-
if (!parsed.code) {
|
|
589
|
-
throw new Error("No authorization code found in input.");
|
|
590
|
-
}
|
|
591
|
-
code = parsed.code;
|
|
592
|
-
}
|
|
583
|
+
const code = await acquireAuthorizationCode(url.toString(), state, callbacks);
|
|
593
584
|
const creds = await exchangeOpenAICode(code, verifier);
|
|
594
585
|
const accountId = getAccountId(creds.accessToken);
|
|
595
586
|
if (!accountId) {
|
|
@@ -620,6 +611,7 @@ function parseAuthorizationInput(input) {
|
|
|
620
611
|
state: params.get("state") ?? void 0
|
|
621
612
|
};
|
|
622
613
|
}
|
|
614
|
+
if (/\s/.test(value) || value.length < MIN_RAW_CODE_LENGTH) return {};
|
|
623
615
|
return { code: value };
|
|
624
616
|
}
|
|
625
617
|
function decodeJwt(token) {
|
|
@@ -638,7 +630,55 @@ function getAccountId(accessToken) {
|
|
|
638
630
|
const accountId = auth?.chatgpt_account_id;
|
|
639
631
|
return typeof accountId === "string" && accountId.length > 0 ? accountId : null;
|
|
640
632
|
}
|
|
641
|
-
async function
|
|
633
|
+
async function acquireAuthorizationCode(authUrl, expectedState, callbacks) {
|
|
634
|
+
callbacks.onOpenUrl(authUrl);
|
|
635
|
+
callbacks.onStatus("Waiting for browser callback...");
|
|
636
|
+
const done = new AbortController();
|
|
637
|
+
try {
|
|
638
|
+
return await new Promise((resolve, reject) => {
|
|
639
|
+
let serverFailed = false;
|
|
640
|
+
let pasteError;
|
|
641
|
+
const failIfExhausted = () => {
|
|
642
|
+
if (!serverFailed || pasteError === void 0) return;
|
|
643
|
+
reject(
|
|
644
|
+
pasteError instanceof Error ? pasteError : new Error("Could not obtain an authorization code.")
|
|
645
|
+
);
|
|
646
|
+
};
|
|
647
|
+
listenForCallback(expectedState, done.signal).then(resolve, () => {
|
|
648
|
+
serverFailed = true;
|
|
649
|
+
failIfExhausted();
|
|
650
|
+
});
|
|
651
|
+
promptForCode(expectedState, callbacks, done.signal).then(resolve, (err) => {
|
|
652
|
+
if (err instanceof FatalLoginError) {
|
|
653
|
+
reject(err);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
pasteError = err;
|
|
657
|
+
failIfExhausted();
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
} finally {
|
|
661
|
+
done.abort();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
var FatalLoginError = class extends Error {
|
|
665
|
+
};
|
|
666
|
+
async function promptForCode(expectedState, callbacks, signal) {
|
|
667
|
+
let message = "If the browser is on another machine (SSH/headless), paste the callback URL or code here:";
|
|
668
|
+
for (let attempt = 0; attempt < MAX_PASTE_ATTEMPTS; attempt++) {
|
|
669
|
+
if (signal.aborted) throw new Error("Authorization code already received.");
|
|
670
|
+
const raw = await callbacks.onPromptCode(message, signal);
|
|
671
|
+
if (signal.aborted) throw new Error("Authorization code already received.");
|
|
672
|
+
const parsed = parseAuthorizationInput(raw);
|
|
673
|
+
if (parsed.code && parsed.state && parsed.state !== expectedState) {
|
|
674
|
+
throw new FatalLoginError("Authorization state mismatch \u2014 start the login again.");
|
|
675
|
+
}
|
|
676
|
+
if (parsed.code) return parsed.code;
|
|
677
|
+
message = "That didn't contain an authorization code. Paste the full callback URL:";
|
|
678
|
+
}
|
|
679
|
+
throw new Error("No authorization code found in input.");
|
|
680
|
+
}
|
|
681
|
+
async function listenForCallback(expectedState, signal) {
|
|
642
682
|
return new Promise((resolve, reject) => {
|
|
643
683
|
let receivedCode = null;
|
|
644
684
|
const server = http.createServer((req, res) => {
|
|
@@ -661,18 +701,18 @@ async function loginWithServer(authUrl, expectedState, callbacks) {
|
|
|
661
701
|
server.on("error", (err) => {
|
|
662
702
|
reject(err);
|
|
663
703
|
});
|
|
664
|
-
server.listen(1455, "127.0.0.1"
|
|
665
|
-
callbacks.onOpenUrl(authUrl);
|
|
666
|
-
callbacks.onStatus("Waiting for browser callback...");
|
|
667
|
-
});
|
|
704
|
+
server.listen(1455, "127.0.0.1");
|
|
668
705
|
const timeout = setTimeout(() => {
|
|
669
|
-
if (!receivedCode)
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
}, 12e4);
|
|
706
|
+
if (!receivedCode) server.close();
|
|
707
|
+
}, CALLBACK_TIMEOUT_MS);
|
|
673
708
|
timeout.unref();
|
|
709
|
+
const onAbort = () => {
|
|
710
|
+
server.close();
|
|
711
|
+
};
|
|
712
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
674
713
|
server.on("close", () => {
|
|
675
714
|
clearTimeout(timeout);
|
|
715
|
+
signal.removeEventListener("abort", onAbort);
|
|
676
716
|
if (receivedCode) {
|
|
677
717
|
resolve(receivedCode);
|
|
678
718
|
} else {
|
|
@@ -781,7 +821,7 @@ async function loginGemini(callbacks) {
|
|
|
781
821
|
url.searchParams.set("state", state);
|
|
782
822
|
let code;
|
|
783
823
|
try {
|
|
784
|
-
code = await
|
|
824
|
+
code = await loginWithServer(url.toString(), redirectUri, state, callbacks);
|
|
785
825
|
} catch {
|
|
786
826
|
callbacks.onOpenUrl(url.toString());
|
|
787
827
|
const raw = await callbacks.onPromptCode(
|
|
@@ -859,7 +899,7 @@ function parseAuthorizationInput2(input) {
|
|
|
859
899
|
}
|
|
860
900
|
return { code: value };
|
|
861
901
|
}
|
|
862
|
-
async function
|
|
902
|
+
async function loginWithServer(authUrl, redirectUri, expectedState, callbacks) {
|
|
863
903
|
const redirect = new URL(redirectUri);
|
|
864
904
|
const port = Number(redirect.port);
|
|
865
905
|
return new Promise((resolve, reject) => {
|
|
@@ -1685,12 +1725,20 @@ var AuthStorage = class {
|
|
|
1685
1725
|
}
|
|
1686
1726
|
/**
|
|
1687
1727
|
* Returns valid credentials, auto-refreshing if expired.
|
|
1728
|
+
*
|
|
1688
1729
|
* If `forceRefresh` is true, refreshes even if the token hasn't expired
|
|
1689
|
-
* (useful when the provider rejects a token with 401 before its stored
|
|
1730
|
+
* (useful when the provider rejects a token with 401 before its stored
|
|
1731
|
+
* expiry). Callers recovering from a rejection should also pass
|
|
1732
|
+
* `rejectedToken` — see the stampede guard below.
|
|
1733
|
+
*
|
|
1690
1734
|
* Throws if not logged in.
|
|
1691
1735
|
*/
|
|
1692
1736
|
async resolveCredentials(provider, opts) {
|
|
1693
|
-
|
|
1737
|
+
if (opts?.forceRefresh) {
|
|
1738
|
+
await this.ensureLoaded();
|
|
1739
|
+
} else {
|
|
1740
|
+
await this.ensureFresh();
|
|
1741
|
+
}
|
|
1694
1742
|
const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : providerStorageKeys(provider);
|
|
1695
1743
|
if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
|
|
1696
1744
|
await this.reloadLatest();
|
|
@@ -1716,7 +1764,8 @@ var AuthStorage = class {
|
|
|
1716
1764
|
}
|
|
1717
1765
|
try {
|
|
1718
1766
|
return await this.resolveCredentials(dual.oauthKey, {
|
|
1719
|
-
...opts?.forceRefresh ? { forceRefresh: true } : {}
|
|
1767
|
+
...opts?.forceRefresh ? { forceRefresh: true } : {},
|
|
1768
|
+
...opts?.rejectedToken !== void 0 ? { rejectedToken: opts.rejectedToken } : {}
|
|
1720
1769
|
});
|
|
1721
1770
|
} catch (err) {
|
|
1722
1771
|
if (err instanceof NotLoggedInError && this.data[dual.provider]) {
|
|
@@ -1750,7 +1799,15 @@ var AuthStorage = class {
|
|
|
1750
1799
|
throw new NotLoggedInError(provider);
|
|
1751
1800
|
}
|
|
1752
1801
|
const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
|
|
1753
|
-
|
|
1802
|
+
const rotatedBySibling = opts?.rejectedToken !== void 0 && latestCreds.accessToken !== opts.rejectedToken;
|
|
1803
|
+
if (credentialWasReplaced || rotatedBySibling || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - refreshThresholdMs(latestCreds)) {
|
|
1804
|
+
if (rotatedBySibling && !credentialWasReplaced) {
|
|
1805
|
+
log(
|
|
1806
|
+
"INFO",
|
|
1807
|
+
"auth",
|
|
1808
|
+
`${provider} token was rotated by another gg process \u2014 adopting it instead of refreshing again`
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1754
1811
|
this.data = latest;
|
|
1755
1812
|
return latestCreds;
|
|
1756
1813
|
}
|
|
@@ -1788,6 +1845,7 @@ var AuthStorage = class {
|
|
|
1788
1845
|
return await refreshPromise;
|
|
1789
1846
|
} finally {
|
|
1790
1847
|
this.refreshLocks.delete(provider);
|
|
1848
|
+
await this.rememberSnapshot();
|
|
1791
1849
|
}
|
|
1792
1850
|
}
|
|
1793
1851
|
/**
|
|
@@ -2410,4 +2468,4 @@ export {
|
|
|
2410
2468
|
getSummaryModel,
|
|
2411
2469
|
getFastModel
|
|
2412
2470
|
};
|
|
2413
|
-
//# sourceMappingURL=chunk-
|
|
2471
|
+
//# sourceMappingURL=chunk-JH7OVHH5.js.map
|