@omnicross/subscriptions 0.2.1 → 0.3.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.
- package/LICENSE +21 -21
- package/NOTICE +16 -16
- package/README.md +15 -15
- package/dist/{chunk-UXUMAXZJ.cjs → chunk-B2LHAP4F.cjs} +191 -15
- package/dist/{chunk-4HYDPKHR.js → chunk-ZB3GA2Y2.js} +194 -18
- package/dist/index.cjs +127 -63
- package/dist/index.d.cts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +77 -13
- package/dist/oauth.cjs +6 -2
- package/dist/oauth.d.cts +118 -1
- package/dist/oauth.d.ts +118 -1
- package/dist/oauth.js +7 -3
- package/package.json +3 -3
|
@@ -2,6 +2,180 @@ import {
|
|
|
2
2
|
__export
|
|
3
3
|
} from "./chunk-MLKGABMK.js";
|
|
4
4
|
|
|
5
|
+
// src/oauth/flows/kimi.ts
|
|
6
|
+
var kimi_exports = {};
|
|
7
|
+
__export(kimi_exports, {
|
|
8
|
+
KIMI_CLI_VERSION: () => KIMI_CLI_VERSION,
|
|
9
|
+
KIMI_OAUTH_CONFIG: () => KIMI_OAUTH_CONFIG,
|
|
10
|
+
awaitDeviceToken: () => awaitDeviceToken,
|
|
11
|
+
generateKimiDeviceId: () => generateKimiDeviceId,
|
|
12
|
+
kimiAccountIdFromAccessToken: () => kimiAccountIdFromAccessToken,
|
|
13
|
+
kimiFingerprintHeaders: () => kimiFingerprintHeaders,
|
|
14
|
+
pollDeviceToken: () => pollDeviceToken,
|
|
15
|
+
refreshAccessToken: () => refreshAccessToken,
|
|
16
|
+
requestDeviceAuthorization: () => requestDeviceAuthorization
|
|
17
|
+
});
|
|
18
|
+
import crypto from "crypto";
|
|
19
|
+
import * as os from "os";
|
|
20
|
+
var KIMI_OAUTH_CONFIG = {
|
|
21
|
+
clientId: "17e5f671-d194-4dfb-9706-5516cb48c098",
|
|
22
|
+
deviceAuthorizationEndpoint: "https://auth.kimi.com/api/oauth/device_authorization",
|
|
23
|
+
tokenEndpoint: "https://auth.kimi.com/api/oauth/token"
|
|
24
|
+
};
|
|
25
|
+
var KIMI_CLI_VERSION = process.env["KIMI_CLI_VERSION"] ?? "1.0.0";
|
|
26
|
+
function sanitizeHeaderValue(value, fallback = "") {
|
|
27
|
+
const sanitized = value.replace(/[^\x20-\x7E]/g, "").trim();
|
|
28
|
+
return sanitized || fallback;
|
|
29
|
+
}
|
|
30
|
+
function deviceModel() {
|
|
31
|
+
const platform2 = os.platform();
|
|
32
|
+
const label = platform2 === "darwin" ? "macOS" : platform2 === "win32" ? "Windows" : platform2 === "linux" ? "Linux" : platform2;
|
|
33
|
+
return [label, os.release(), os.arch()].filter(Boolean).join(" ").trim();
|
|
34
|
+
}
|
|
35
|
+
function kimiFingerprintHeaders(deviceId) {
|
|
36
|
+
return {
|
|
37
|
+
"User-Agent": `KimiCLI/${KIMI_CLI_VERSION}`,
|
|
38
|
+
"X-Msh-Platform": "kimi_cli",
|
|
39
|
+
"X-Msh-Version": KIMI_CLI_VERSION,
|
|
40
|
+
"X-Msh-Device-Name": sanitizeHeaderValue(os.hostname(), "unknown"),
|
|
41
|
+
"X-Msh-Device-Model": sanitizeHeaderValue(deviceModel(), "unknown"),
|
|
42
|
+
"X-Msh-Os-Version": sanitizeHeaderValue(os.version(), "unknown"),
|
|
43
|
+
...deviceId ? { "X-Msh-Device-Id": sanitizeHeaderValue(deviceId) } : {}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function generateKimiDeviceId() {
|
|
47
|
+
return crypto.randomUUID().replace(/-/g, "");
|
|
48
|
+
}
|
|
49
|
+
async function postFormRaw(fetchImpl, url, params, headers, timeoutMs = 3e4) {
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
52
|
+
let response;
|
|
53
|
+
try {
|
|
54
|
+
response = await fetchImpl(url, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json", ...headers },
|
|
57
|
+
body: params.toString(),
|
|
58
|
+
signal: controller.signal
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (controller.signal.aborted) throw new Error("token endpoint timed out");
|
|
62
|
+
throw error;
|
|
63
|
+
} finally {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
}
|
|
66
|
+
const text = await response.text();
|
|
67
|
+
let body;
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(text);
|
|
70
|
+
body = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
71
|
+
} catch {
|
|
72
|
+
body = {};
|
|
73
|
+
}
|
|
74
|
+
return { status: response.status, body };
|
|
75
|
+
}
|
|
76
|
+
async function requestDeviceAuthorization(fetchImpl, fingerprint) {
|
|
77
|
+
const { status, body } = await postFormRaw(
|
|
78
|
+
fetchImpl,
|
|
79
|
+
KIMI_OAUTH_CONFIG.deviceAuthorizationEndpoint,
|
|
80
|
+
new URLSearchParams({ client_id: KIMI_OAUTH_CONFIG.clientId }),
|
|
81
|
+
fingerprint ?? {}
|
|
82
|
+
);
|
|
83
|
+
const userCode = typeof body["user_code"] === "string" ? body["user_code"] : void 0;
|
|
84
|
+
const deviceCode = typeof body["device_code"] === "string" ? body["device_code"] : void 0;
|
|
85
|
+
const verificationUri = typeof body["verification_uri"] === "string" ? body["verification_uri"] : void 0;
|
|
86
|
+
if (status >= 400 || !userCode || !deviceCode || !verificationUri) {
|
|
87
|
+
const message = typeof body["error_description"] === "string" ? body["error_description"] : typeof body["msg"] === "string" ? body["msg"] : `device authorization failed (HTTP ${status})`;
|
|
88
|
+
throw new Error(message);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
userCode,
|
|
92
|
+
deviceCode,
|
|
93
|
+
verificationUri,
|
|
94
|
+
...typeof body["verification_uri_complete"] === "string" ? { verificationUriComplete: body["verification_uri_complete"] } : {},
|
|
95
|
+
...typeof body["interval"] === "number" ? { interval: body["interval"] } : {},
|
|
96
|
+
...typeof body["expires_in"] === "number" ? { expiresIn: body["expires_in"] } : {}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async function pollDeviceToken(deviceCode, fetchImpl, fingerprint) {
|
|
100
|
+
const { status, body } = await postFormRaw(
|
|
101
|
+
fetchImpl,
|
|
102
|
+
KIMI_OAUTH_CONFIG.tokenEndpoint,
|
|
103
|
+
new URLSearchParams({
|
|
104
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
105
|
+
client_id: KIMI_OAUTH_CONFIG.clientId,
|
|
106
|
+
device_code: deviceCode
|
|
107
|
+
}),
|
|
108
|
+
fingerprint ?? {}
|
|
109
|
+
);
|
|
110
|
+
const accessToken = typeof body["access_token"] === "string" ? body["access_token"] : void 0;
|
|
111
|
+
const refreshToken = typeof body["refresh_token"] === "string" ? body["refresh_token"] : void 0;
|
|
112
|
+
if (accessToken && refreshToken) {
|
|
113
|
+
const expiresIn = typeof body["expires_in"] === "number" && body["expires_in"] > 0 ? body["expires_in"] : 3600;
|
|
114
|
+
return { state: "done", accessToken, refreshToken, expiresIn };
|
|
115
|
+
}
|
|
116
|
+
const error = typeof body["error"] === "string" ? body["error"] : void 0;
|
|
117
|
+
if (error === "authorization_pending") return { state: "pending" };
|
|
118
|
+
if (error === "slow_down") return { state: "pending", intervalSeconds: 5 };
|
|
119
|
+
if (status < 400 && !error) return { state: "pending" };
|
|
120
|
+
const message = typeof body["error_description"] === "string" && body["error_description"] ? body["error_description"] : error ?? `device token poll failed (HTTP ${status})`;
|
|
121
|
+
return { state: "failed", message };
|
|
122
|
+
}
|
|
123
|
+
async function awaitDeviceToken(authorization, fetchImpl, options = {}) {
|
|
124
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
125
|
+
const deadline = Date.now() + (options.deadlineMs ?? 15 * 6e4);
|
|
126
|
+
const baseIntervalMs = options.intervalMs ?? (authorization.interval ?? 5) * 1e3;
|
|
127
|
+
let intervalMs = Math.max(1e3, baseIntervalMs);
|
|
128
|
+
for (; ; ) {
|
|
129
|
+
const result = await pollDeviceToken(authorization.deviceCode, fetchImpl, options.fingerprint);
|
|
130
|
+
if (result.state === "done") return result;
|
|
131
|
+
if (result.state === "failed") throw new Error(result.message);
|
|
132
|
+
if (result.state === "pending" && result.intervalSeconds) intervalMs += result.intervalSeconds * 1e3;
|
|
133
|
+
options.onPending?.();
|
|
134
|
+
if (Date.now() + intervalMs > deadline) throw new Error("device authorization timed out");
|
|
135
|
+
await sleep(intervalMs);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function refreshAccessToken(refreshToken, fetchImpl, fingerprint) {
|
|
139
|
+
const { status, body } = await postFormRaw(
|
|
140
|
+
fetchImpl,
|
|
141
|
+
KIMI_OAUTH_CONFIG.tokenEndpoint,
|
|
142
|
+
new URLSearchParams({
|
|
143
|
+
grant_type: "refresh_token",
|
|
144
|
+
client_id: KIMI_OAUTH_CONFIG.clientId,
|
|
145
|
+
refresh_token: refreshToken
|
|
146
|
+
}),
|
|
147
|
+
fingerprint ?? {}
|
|
148
|
+
);
|
|
149
|
+
const accessToken = typeof body["access_token"] === "string" ? body["access_token"] : void 0;
|
|
150
|
+
if (status >= 400 || !accessToken) {
|
|
151
|
+
const message = typeof body["error_description"] === "string" && body["error_description"] ? body["error_description"] : typeof body["error"] === "string" ? body["error"] : `refresh failed (HTTP ${status})`;
|
|
152
|
+
throw new Error(message);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
accessToken,
|
|
156
|
+
// Kimi rotates the refresh token; keep the old one when the response omits it.
|
|
157
|
+
refreshToken: typeof body["refresh_token"] === "string" && body["refresh_token"] ? body["refresh_token"] : refreshToken,
|
|
158
|
+
expiresIn: typeof body["expires_in"] === "number" && body["expires_in"] > 0 ? body["expires_in"] : 3600
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function kimiAccountIdFromAccessToken(accessToken) {
|
|
162
|
+
const parts = accessToken.split(".");
|
|
163
|
+
if (parts.length !== 3) return void 0;
|
|
164
|
+
try {
|
|
165
|
+
const json = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
166
|
+
const claims = JSON.parse(json);
|
|
167
|
+
if (!claims || typeof claims !== "object" || Array.isArray(claims)) return void 0;
|
|
168
|
+
const record = claims;
|
|
169
|
+
for (const key of ["user_id", "sub"]) {
|
|
170
|
+
const value = record[key];
|
|
171
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
172
|
+
}
|
|
173
|
+
return void 0;
|
|
174
|
+
} catch {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
5
179
|
// src/oauth/flows/claude.ts
|
|
6
180
|
var claude_exports = {};
|
|
7
181
|
__export(claude_exports, {
|
|
@@ -9,9 +183,9 @@ __export(claude_exports, {
|
|
|
9
183
|
exchangeSetupTokenCode: () => exchangeSetupTokenCode,
|
|
10
184
|
generateAuthParams: () => generateAuthParams,
|
|
11
185
|
generateSetupTokenParams: () => generateSetupTokenParams,
|
|
12
|
-
refreshAccessToken: () =>
|
|
186
|
+
refreshAccessToken: () => refreshAccessToken2
|
|
13
187
|
});
|
|
14
|
-
import
|
|
188
|
+
import crypto2 from "crypto";
|
|
15
189
|
|
|
16
190
|
// src/oauth/fetchPort.ts
|
|
17
191
|
function errorMessage(error, errorDescription) {
|
|
@@ -128,9 +302,9 @@ var SETUP_TOKEN_CONFIG = {
|
|
|
128
302
|
// Only inference permission, no API key creation
|
|
129
303
|
};
|
|
130
304
|
function generatePkce() {
|
|
131
|
-
const codeVerifier =
|
|
132
|
-
const codeChallenge =
|
|
133
|
-
const state =
|
|
305
|
+
const codeVerifier = crypto2.randomBytes(32).toString("base64url");
|
|
306
|
+
const codeChallenge = crypto2.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
307
|
+
const state = crypto2.randomBytes(16).toString("hex");
|
|
134
308
|
return { codeVerifier, codeChallenge, state };
|
|
135
309
|
}
|
|
136
310
|
function generateAuthParams() {
|
|
@@ -212,7 +386,7 @@ async function exchangeSetupTokenCode(request, fetchImpl) {
|
|
|
212
386
|
scopes: data.scope?.split(" ") || SETUP_TOKEN_CONFIG.scopes
|
|
213
387
|
};
|
|
214
388
|
}
|
|
215
|
-
async function
|
|
389
|
+
async function refreshAccessToken2(refreshToken, fetchImpl) {
|
|
216
390
|
const data = await postJson(
|
|
217
391
|
fetchImpl,
|
|
218
392
|
CLAUDE_OAUTH_CONFIG.tokenEndpoint,
|
|
@@ -236,9 +410,9 @@ var codex_exports = {};
|
|
|
236
410
|
__export(codex_exports, {
|
|
237
411
|
exchangeCodeForTokens: () => exchangeCodeForTokens2,
|
|
238
412
|
generateAuthParams: () => generateAuthParams2,
|
|
239
|
-
refreshAccessToken: () =>
|
|
413
|
+
refreshAccessToken: () => refreshAccessToken3
|
|
240
414
|
});
|
|
241
|
-
import
|
|
415
|
+
import crypto3 from "crypto";
|
|
242
416
|
var CODEX_OAUTH_CONFIG = {
|
|
243
417
|
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
244
418
|
authorizationEndpoint: "https://auth.openai.com/oauth/authorize",
|
|
@@ -247,9 +421,9 @@ var CODEX_OAUTH_CONFIG = {
|
|
|
247
421
|
scopes: ["openid", "profile", "email", "offline_access"]
|
|
248
422
|
};
|
|
249
423
|
function generateAuthParams2() {
|
|
250
|
-
const codeVerifier =
|
|
251
|
-
const codeChallenge =
|
|
252
|
-
const state =
|
|
424
|
+
const codeVerifier = crypto3.randomBytes(64).toString("hex");
|
|
425
|
+
const codeChallenge = crypto3.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
426
|
+
const state = crypto3.randomBytes(16).toString("hex");
|
|
253
427
|
const params = new URLSearchParams({
|
|
254
428
|
response_type: "code",
|
|
255
429
|
client_id: CODEX_OAUTH_CONFIG.clientId,
|
|
@@ -286,7 +460,7 @@ async function exchangeCodeForTokens2(request, fetchImpl) {
|
|
|
286
460
|
expiresIn: data.expires_in
|
|
287
461
|
};
|
|
288
462
|
}
|
|
289
|
-
async function
|
|
463
|
+
async function refreshAccessToken3(refreshToken, fetchImpl) {
|
|
290
464
|
const params = new URLSearchParams({
|
|
291
465
|
grant_type: "refresh_token",
|
|
292
466
|
client_id: CODEX_OAUTH_CONFIG.clientId,
|
|
@@ -312,9 +486,9 @@ var gemini_exports = {};
|
|
|
312
486
|
__export(gemini_exports, {
|
|
313
487
|
exchangeCodeForTokens: () => exchangeCodeForTokens3,
|
|
314
488
|
generateAuthParams: () => generateAuthParams3,
|
|
315
|
-
refreshAccessToken: () =>
|
|
489
|
+
refreshAccessToken: () => refreshAccessToken4
|
|
316
490
|
});
|
|
317
|
-
import
|
|
491
|
+
import crypto4 from "crypto";
|
|
318
492
|
var GEMINI_OAUTH_CONFIG = {
|
|
319
493
|
clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
|
|
320
494
|
// The Gemini CLI's *public* installed-app OAuth client secret (mirrors the
|
|
@@ -328,9 +502,9 @@ var GEMINI_OAUTH_CONFIG = {
|
|
|
328
502
|
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
|
|
329
503
|
};
|
|
330
504
|
function generateAuthParams3() {
|
|
331
|
-
const codeVerifier =
|
|
332
|
-
const codeChallenge =
|
|
333
|
-
const state =
|
|
505
|
+
const codeVerifier = crypto4.randomBytes(32).toString("base64url");
|
|
506
|
+
const codeChallenge = crypto4.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
507
|
+
const state = crypto4.randomBytes(16).toString("hex");
|
|
334
508
|
const params = new URLSearchParams({
|
|
335
509
|
client_id: GEMINI_OAUTH_CONFIG.clientId,
|
|
336
510
|
redirect_uri: GEMINI_OAUTH_CONFIG.redirectUri,
|
|
@@ -368,7 +542,7 @@ async function exchangeCodeForTokens3(authorizationCode, codeVerifier, fetchImpl
|
|
|
368
542
|
expiresIn: data.expires_in
|
|
369
543
|
};
|
|
370
544
|
}
|
|
371
|
-
async function
|
|
545
|
+
async function refreshAccessToken4(refreshToken, fetchImpl) {
|
|
372
546
|
const params = new URLSearchParams({
|
|
373
547
|
grant_type: "refresh_token",
|
|
374
548
|
client_id: GEMINI_OAUTH_CONFIG.clientId,
|
|
@@ -388,6 +562,8 @@ async function refreshAccessToken3(refreshToken, fetchImpl) {
|
|
|
388
562
|
}
|
|
389
563
|
|
|
390
564
|
export {
|
|
565
|
+
kimiFingerprintHeaders,
|
|
566
|
+
kimi_exports,
|
|
391
567
|
claude_exports,
|
|
392
568
|
codex_exports,
|
|
393
569
|
gemini_exports
|