@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
package/dist/index.cjs
CHANGED
|
@@ -397,6 +397,7 @@ var import_node_path3 = __toESM(require("path"), 1);
|
|
|
397
397
|
var import_node_crypto2 = require("crypto");
|
|
398
398
|
var import_gg_ai = require("@kenkaiiii/gg-ai");
|
|
399
399
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
400
|
+
var MIN_HEADROOM_BYTES = 64 * 1024;
|
|
400
401
|
var fd = null;
|
|
401
402
|
var bytesWritten = 0;
|
|
402
403
|
var capped = false;
|
|
@@ -407,7 +408,7 @@ var exactSecrets = [];
|
|
|
407
408
|
function rotateIfNeeded(filePath) {
|
|
408
409
|
try {
|
|
409
410
|
const st = import_node_fs2.default.statSync(filePath);
|
|
410
|
-
if (st.size
|
|
411
|
+
if (st.size <= MAX_BYTES - MIN_HEADROOM_BYTES) return;
|
|
411
412
|
const rotated = `${filePath}.1`;
|
|
412
413
|
try {
|
|
413
414
|
import_node_fs2.default.unlinkSync(rotated);
|
|
@@ -702,6 +703,9 @@ var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
|
702
703
|
var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
|
|
703
704
|
var SCOPE = "openid profile email offline_access api.connectors.read api.connectors.invoke";
|
|
704
705
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
706
|
+
var CALLBACK_TIMEOUT_MS = 12e4;
|
|
707
|
+
var MAX_PASTE_ATTEMPTS = 3;
|
|
708
|
+
var MIN_RAW_CODE_LENGTH = 10;
|
|
705
709
|
async function loginOpenAI(callbacks) {
|
|
706
710
|
const { verifier, challenge } = await generatePKCE();
|
|
707
711
|
const state = import_node_crypto4.default.randomBytes(16).toString("hex");
|
|
@@ -717,20 +721,7 @@ async function loginOpenAI(callbacks) {
|
|
|
717
721
|
url.searchParams.set("id_token_add_organizations", "true");
|
|
718
722
|
url.searchParams.set("codex_cli_simplified_flow", "true");
|
|
719
723
|
url.searchParams.set("originator", "ggcoder");
|
|
720
|
-
|
|
721
|
-
try {
|
|
722
|
-
code = await loginWithServer(url.toString(), state, callbacks);
|
|
723
|
-
} catch {
|
|
724
|
-
callbacks.onOpenUrl(url.toString());
|
|
725
|
-
const raw = await callbacks.onPromptCode(
|
|
726
|
-
"Could not start local server. Paste the callback URL or code from the browser:"
|
|
727
|
-
);
|
|
728
|
-
const parsed = parseAuthorizationInput(raw);
|
|
729
|
-
if (!parsed.code) {
|
|
730
|
-
throw new Error("No authorization code found in input.");
|
|
731
|
-
}
|
|
732
|
-
code = parsed.code;
|
|
733
|
-
}
|
|
724
|
+
const code = await acquireAuthorizationCode(url.toString(), state, callbacks);
|
|
734
725
|
const creds = await exchangeOpenAICode(code, verifier);
|
|
735
726
|
const accountId = getAccountId(creds.accessToken);
|
|
736
727
|
if (!accountId) {
|
|
@@ -761,6 +752,7 @@ function parseAuthorizationInput(input) {
|
|
|
761
752
|
state: params.get("state") ?? void 0
|
|
762
753
|
};
|
|
763
754
|
}
|
|
755
|
+
if (/\s/.test(value) || value.length < MIN_RAW_CODE_LENGTH) return {};
|
|
764
756
|
return { code: value };
|
|
765
757
|
}
|
|
766
758
|
function decodeJwt(token) {
|
|
@@ -779,7 +771,55 @@ function getAccountId(accessToken) {
|
|
|
779
771
|
const accountId = auth?.chatgpt_account_id;
|
|
780
772
|
return typeof accountId === "string" && accountId.length > 0 ? accountId : null;
|
|
781
773
|
}
|
|
782
|
-
async function
|
|
774
|
+
async function acquireAuthorizationCode(authUrl, expectedState, callbacks) {
|
|
775
|
+
callbacks.onOpenUrl(authUrl);
|
|
776
|
+
callbacks.onStatus("Waiting for browser callback...");
|
|
777
|
+
const done = new AbortController();
|
|
778
|
+
try {
|
|
779
|
+
return await new Promise((resolve, reject) => {
|
|
780
|
+
let serverFailed = false;
|
|
781
|
+
let pasteError;
|
|
782
|
+
const failIfExhausted = () => {
|
|
783
|
+
if (!serverFailed || pasteError === void 0) return;
|
|
784
|
+
reject(
|
|
785
|
+
pasteError instanceof Error ? pasteError : new Error("Could not obtain an authorization code.")
|
|
786
|
+
);
|
|
787
|
+
};
|
|
788
|
+
listenForCallback(expectedState, done.signal).then(resolve, () => {
|
|
789
|
+
serverFailed = true;
|
|
790
|
+
failIfExhausted();
|
|
791
|
+
});
|
|
792
|
+
promptForCode(expectedState, callbacks, done.signal).then(resolve, (err) => {
|
|
793
|
+
if (err instanceof FatalLoginError) {
|
|
794
|
+
reject(err);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
pasteError = err;
|
|
798
|
+
failIfExhausted();
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
} finally {
|
|
802
|
+
done.abort();
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
var FatalLoginError = class extends Error {
|
|
806
|
+
};
|
|
807
|
+
async function promptForCode(expectedState, callbacks, signal) {
|
|
808
|
+
let message = "If the browser is on another machine (SSH/headless), paste the callback URL or code here:";
|
|
809
|
+
for (let attempt = 0; attempt < MAX_PASTE_ATTEMPTS; attempt++) {
|
|
810
|
+
if (signal.aborted) throw new Error("Authorization code already received.");
|
|
811
|
+
const raw = await callbacks.onPromptCode(message, signal);
|
|
812
|
+
if (signal.aborted) throw new Error("Authorization code already received.");
|
|
813
|
+
const parsed = parseAuthorizationInput(raw);
|
|
814
|
+
if (parsed.code && parsed.state && parsed.state !== expectedState) {
|
|
815
|
+
throw new FatalLoginError("Authorization state mismatch \u2014 start the login again.");
|
|
816
|
+
}
|
|
817
|
+
if (parsed.code) return parsed.code;
|
|
818
|
+
message = "That didn't contain an authorization code. Paste the full callback URL:";
|
|
819
|
+
}
|
|
820
|
+
throw new Error("No authorization code found in input.");
|
|
821
|
+
}
|
|
822
|
+
async function listenForCallback(expectedState, signal) {
|
|
783
823
|
return new Promise((resolve, reject) => {
|
|
784
824
|
let receivedCode = null;
|
|
785
825
|
const server = import_node_http.default.createServer((req, res) => {
|
|
@@ -802,18 +842,18 @@ async function loginWithServer(authUrl, expectedState, callbacks) {
|
|
|
802
842
|
server.on("error", (err) => {
|
|
803
843
|
reject(err);
|
|
804
844
|
});
|
|
805
|
-
server.listen(1455, "127.0.0.1"
|
|
806
|
-
callbacks.onOpenUrl(authUrl);
|
|
807
|
-
callbacks.onStatus("Waiting for browser callback...");
|
|
808
|
-
});
|
|
845
|
+
server.listen(1455, "127.0.0.1");
|
|
809
846
|
const timeout = setTimeout(() => {
|
|
810
|
-
if (!receivedCode)
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
}, 12e4);
|
|
847
|
+
if (!receivedCode) server.close();
|
|
848
|
+
}, CALLBACK_TIMEOUT_MS);
|
|
814
849
|
timeout.unref();
|
|
850
|
+
const onAbort = () => {
|
|
851
|
+
server.close();
|
|
852
|
+
};
|
|
853
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
815
854
|
server.on("close", () => {
|
|
816
855
|
clearTimeout(timeout);
|
|
856
|
+
signal.removeEventListener("abort", onAbort);
|
|
817
857
|
if (receivedCode) {
|
|
818
858
|
resolve(receivedCode);
|
|
819
859
|
} else {
|
|
@@ -922,7 +962,7 @@ async function loginGemini(callbacks) {
|
|
|
922
962
|
url.searchParams.set("state", state);
|
|
923
963
|
let code;
|
|
924
964
|
try {
|
|
925
|
-
code = await
|
|
965
|
+
code = await loginWithServer(url.toString(), redirectUri, state, callbacks);
|
|
926
966
|
} catch {
|
|
927
967
|
callbacks.onOpenUrl(url.toString());
|
|
928
968
|
const raw = await callbacks.onPromptCode(
|
|
@@ -1000,7 +1040,7 @@ function parseAuthorizationInput2(input) {
|
|
|
1000
1040
|
}
|
|
1001
1041
|
return { code: value };
|
|
1002
1042
|
}
|
|
1003
|
-
async function
|
|
1043
|
+
async function loginWithServer(authUrl, redirectUri, expectedState, callbacks) {
|
|
1004
1044
|
const redirect = new URL(redirectUri);
|
|
1005
1045
|
const port = Number(redirect.port);
|
|
1006
1046
|
return new Promise((resolve, reject) => {
|
|
@@ -1826,12 +1866,20 @@ var AuthStorage = class {
|
|
|
1826
1866
|
}
|
|
1827
1867
|
/**
|
|
1828
1868
|
* Returns valid credentials, auto-refreshing if expired.
|
|
1869
|
+
*
|
|
1829
1870
|
* If `forceRefresh` is true, refreshes even if the token hasn't expired
|
|
1830
|
-
* (useful when the provider rejects a token with 401 before its stored
|
|
1871
|
+
* (useful when the provider rejects a token with 401 before its stored
|
|
1872
|
+
* expiry). Callers recovering from a rejection should also pass
|
|
1873
|
+
* `rejectedToken` — see the stampede guard below.
|
|
1874
|
+
*
|
|
1831
1875
|
* Throws if not logged in.
|
|
1832
1876
|
*/
|
|
1833
1877
|
async resolveCredentials(provider, opts) {
|
|
1834
|
-
|
|
1878
|
+
if (opts?.forceRefresh) {
|
|
1879
|
+
await this.ensureLoaded();
|
|
1880
|
+
} else {
|
|
1881
|
+
await this.ensureFresh();
|
|
1882
|
+
}
|
|
1835
1883
|
const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : providerStorageKeys(provider);
|
|
1836
1884
|
if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
|
|
1837
1885
|
await this.reloadLatest();
|
|
@@ -1857,7 +1905,8 @@ var AuthStorage = class {
|
|
|
1857
1905
|
}
|
|
1858
1906
|
try {
|
|
1859
1907
|
return await this.resolveCredentials(dual.oauthKey, {
|
|
1860
|
-
...opts?.forceRefresh ? { forceRefresh: true } : {}
|
|
1908
|
+
...opts?.forceRefresh ? { forceRefresh: true } : {},
|
|
1909
|
+
...opts?.rejectedToken !== void 0 ? { rejectedToken: opts.rejectedToken } : {}
|
|
1861
1910
|
});
|
|
1862
1911
|
} catch (err) {
|
|
1863
1912
|
if (err instanceof NotLoggedInError && this.data[dual.provider]) {
|
|
@@ -1891,7 +1940,15 @@ var AuthStorage = class {
|
|
|
1891
1940
|
throw new NotLoggedInError(provider);
|
|
1892
1941
|
}
|
|
1893
1942
|
const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
|
|
1894
|
-
|
|
1943
|
+
const rotatedBySibling = opts?.rejectedToken !== void 0 && latestCreds.accessToken !== opts.rejectedToken;
|
|
1944
|
+
if (credentialWasReplaced || rotatedBySibling || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - refreshThresholdMs(latestCreds)) {
|
|
1945
|
+
if (rotatedBySibling && !credentialWasReplaced) {
|
|
1946
|
+
log(
|
|
1947
|
+
"INFO",
|
|
1948
|
+
"auth",
|
|
1949
|
+
`${provider} token was rotated by another gg process \u2014 adopting it instead of refreshing again`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1895
1952
|
this.data = latest;
|
|
1896
1953
|
return latestCreds;
|
|
1897
1954
|
}
|
|
@@ -1929,6 +1986,7 @@ var AuthStorage = class {
|
|
|
1929
1986
|
return await refreshPromise;
|
|
1930
1987
|
} finally {
|
|
1931
1988
|
this.refreshLocks.delete(provider);
|
|
1989
|
+
await this.rememberSnapshot();
|
|
1932
1990
|
}
|
|
1933
1991
|
}
|
|
1934
1992
|
/**
|