@itssimplereally/opencode-kimicode-auth 0.1.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/LICENSE +22 -0
- package/README.md +87 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/src/constants.d.ts +69 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +207 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/kimi/oauth.d.ts +64 -0
- package/dist/src/kimi/oauth.d.ts.map +1 -0
- package/dist/src/kimi/oauth.js +130 -0
- package/dist/src/kimi/oauth.js.map +1 -0
- package/dist/src/plugin/accounts.d.ts +167 -0
- package/dist/src/plugin/accounts.d.ts.map +1 -0
- package/dist/src/plugin/accounts.js +843 -0
- package/dist/src/plugin/accounts.js.map +1 -0
- package/dist/src/plugin/auth.d.ts +13 -0
- package/dist/src/plugin/auth.d.ts.map +1 -0
- package/dist/src/plugin/auth.js +26 -0
- package/dist/src/plugin/auth.js.map +1 -0
- package/dist/src/plugin/cache.d.ts +14 -0
- package/dist/src/plugin/cache.d.ts.map +1 -0
- package/dist/src/plugin/cache.js +56 -0
- package/dist/src/plugin/cache.js.map +1 -0
- package/dist/src/plugin/cli.d.ts +21 -0
- package/dist/src/plugin/cli.d.ts.map +1 -0
- package/dist/src/plugin/cli.js +98 -0
- package/dist/src/plugin/cli.js.map +1 -0
- package/dist/src/plugin/config/index.d.ts +16 -0
- package/dist/src/plugin/config/index.d.ts.map +1 -0
- package/dist/src/plugin/config/index.js +16 -0
- package/dist/src/plugin/config/index.js.map +1 -0
- package/dist/src/plugin/config/loader.d.ts +36 -0
- package/dist/src/plugin/config/loader.d.ts.map +1 -0
- package/dist/src/plugin/config/loader.js +182 -0
- package/dist/src/plugin/config/loader.js.map +1 -0
- package/dist/src/plugin/config/models.d.ts +18 -0
- package/dist/src/plugin/config/models.d.ts.map +1 -0
- package/dist/src/plugin/config/models.js +26 -0
- package/dist/src/plugin/config/models.js.map +1 -0
- package/dist/src/plugin/config/schema.d.ts +107 -0
- package/dist/src/plugin/config/schema.d.ts.map +1 -0
- package/dist/src/plugin/config/schema.js +282 -0
- package/dist/src/plugin/config/schema.js.map +1 -0
- package/dist/src/plugin/config/updater.d.ts +55 -0
- package/dist/src/plugin/config/updater.d.ts.map +1 -0
- package/dist/src/plugin/config/updater.js +154 -0
- package/dist/src/plugin/config/updater.js.map +1 -0
- package/dist/src/plugin/debug.d.ts +92 -0
- package/dist/src/plugin/debug.d.ts.map +1 -0
- package/dist/src/plugin/debug.js +406 -0
- package/dist/src/plugin/debug.js.map +1 -0
- package/dist/src/plugin/errors.d.ts +28 -0
- package/dist/src/plugin/errors.d.ts.map +1 -0
- package/dist/src/plugin/errors.js +42 -0
- package/dist/src/plugin/errors.js.map +1 -0
- package/dist/src/plugin/fingerprint.d.ts +41 -0
- package/dist/src/plugin/fingerprint.d.ts.map +1 -0
- package/dist/src/plugin/fingerprint.js +94 -0
- package/dist/src/plugin/fingerprint.js.map +1 -0
- package/dist/src/plugin/logger.d.ts +54 -0
- package/dist/src/plugin/logger.d.ts.map +1 -0
- package/dist/src/plugin/logger.js +120 -0
- package/dist/src/plugin/logger.js.map +1 -0
- package/dist/src/plugin/recovery/constants.d.ts +26 -0
- package/dist/src/plugin/recovery/constants.d.ts.map +1 -0
- package/dist/src/plugin/recovery/constants.js +47 -0
- package/dist/src/plugin/recovery/constants.js.map +1 -0
- package/dist/src/plugin/recovery/index.d.ts +16 -0
- package/dist/src/plugin/recovery/index.d.ts.map +1 -0
- package/dist/src/plugin/recovery/index.js +16 -0
- package/dist/src/plugin/recovery/index.js.map +1 -0
- package/dist/src/plugin/recovery/storage.d.ts +24 -0
- package/dist/src/plugin/recovery/storage.d.ts.map +1 -0
- package/dist/src/plugin/recovery/storage.js +354 -0
- package/dist/src/plugin/recovery/storage.js.map +1 -0
- package/dist/src/plugin/recovery/types.d.ts +116 -0
- package/dist/src/plugin/recovery/types.d.ts.map +1 -0
- package/dist/src/plugin/recovery/types.js +6 -0
- package/dist/src/plugin/recovery/types.js.map +1 -0
- package/dist/src/plugin/recovery.d.ts +63 -0
- package/dist/src/plugin/recovery.d.ts.map +1 -0
- package/dist/src/plugin/recovery.js +331 -0
- package/dist/src/plugin/recovery.js.map +1 -0
- package/dist/src/plugin/refresh-queue.d.ts +101 -0
- package/dist/src/plugin/refresh-queue.d.ts.map +1 -0
- package/dist/src/plugin/refresh-queue.js +248 -0
- package/dist/src/plugin/refresh-queue.js.map +1 -0
- package/dist/src/plugin/rotation.d.ts +169 -0
- package/dist/src/plugin/rotation.d.ts.map +1 -0
- package/dist/src/plugin/rotation.js +328 -0
- package/dist/src/plugin/rotation.js.map +1 -0
- package/dist/src/plugin/storage.d.ts +90 -0
- package/dist/src/plugin/storage.d.ts.map +1 -0
- package/dist/src/plugin/storage.js +450 -0
- package/dist/src/plugin/storage.js.map +1 -0
- package/dist/src/plugin/token.d.ts +19 -0
- package/dist/src/plugin/token.d.ts.map +1 -0
- package/dist/src/plugin/token.js +112 -0
- package/dist/src/plugin/token.js.map +1 -0
- package/dist/src/plugin/types.d.ts +97 -0
- package/dist/src/plugin/types.d.ts.map +1 -0
- package/dist/src/plugin/types.js +1 -0
- package/dist/src/plugin/types.js.map +1 -0
- package/dist/src/plugin/version.d.ts +14 -0
- package/dist/src/plugin/version.d.ts.map +1 -0
- package/dist/src/plugin/version.js +20 -0
- package/dist/src/plugin/version.js.map +1 -0
- package/dist/src/plugin.d.ts +5 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +1077 -0
- package/dist/src/plugin.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, renameSync, copyFileSync, unlinkSync, } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
6
|
+
import lockfile from "proper-lockfile";
|
|
7
|
+
import { createLogger } from "./logger";
|
|
8
|
+
const log = createLogger("storage");
|
|
9
|
+
/**
|
|
10
|
+
* Files/directories that should be gitignored in the config directory.
|
|
11
|
+
* These contain sensitive data or machine-specific state.
|
|
12
|
+
*/
|
|
13
|
+
export const GITIGNORE_ENTRIES = [
|
|
14
|
+
".gitignore",
|
|
15
|
+
"kimicode-accounts.json",
|
|
16
|
+
"kimicode-accounts.json.*.tmp",
|
|
17
|
+
"kimicode-logs/",
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Ensures a .gitignore file exists in the config directory with entries
|
|
21
|
+
* for sensitive files. Creates the file if missing, or appends missing
|
|
22
|
+
* entries if it already exists.
|
|
23
|
+
*/
|
|
24
|
+
export async function ensureGitignore(configDir) {
|
|
25
|
+
const gitignorePath = join(configDir, ".gitignore");
|
|
26
|
+
try {
|
|
27
|
+
let content;
|
|
28
|
+
let existingLines = [];
|
|
29
|
+
try {
|
|
30
|
+
content = await fs.readFile(gitignorePath, "utf-8");
|
|
31
|
+
existingLines = content.split("\n").map((line) => line.trim());
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error.code !== "ENOENT") {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
content = "";
|
|
38
|
+
}
|
|
39
|
+
const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
|
|
40
|
+
if (missingEntries.length === 0) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (content === "") {
|
|
44
|
+
await fs.writeFile(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
|
|
45
|
+
log.info("Created .gitignore in config directory");
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
49
|
+
await fs.appendFile(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
|
|
50
|
+
log.info("Updated .gitignore with missing entries", {
|
|
51
|
+
added: missingEntries,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Non-critical feature
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Synchronous version of ensureGitignore for use in sync code paths.
|
|
61
|
+
*/
|
|
62
|
+
export function ensureGitignoreSync(configDir) {
|
|
63
|
+
const gitignorePath = join(configDir, ".gitignore");
|
|
64
|
+
try {
|
|
65
|
+
let content;
|
|
66
|
+
let existingLines = [];
|
|
67
|
+
if (existsSync(gitignorePath)) {
|
|
68
|
+
content = readFileSync(gitignorePath, "utf-8");
|
|
69
|
+
existingLines = content.split("\n").map((line) => line.trim());
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
content = "";
|
|
73
|
+
}
|
|
74
|
+
const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
|
|
75
|
+
if (missingEntries.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (content === "") {
|
|
79
|
+
writeFileSync(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
|
|
80
|
+
log.info("Created .gitignore in config directory");
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const suffix = content.endsWith("\n") ? "" : "\n";
|
|
84
|
+
appendFileSync(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
|
|
85
|
+
log.info("Updated .gitignore with missing entries", {
|
|
86
|
+
added: missingEntries,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Non-critical feature
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Gets the legacy Windows config directory (%APPDATA%\opencode).
|
|
96
|
+
* Used for migration from older plugin versions.
|
|
97
|
+
*/
|
|
98
|
+
function getLegacyWindowsConfigDir() {
|
|
99
|
+
return join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), "opencode");
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Gets the config directory path, with the following precedence:
|
|
103
|
+
* 1. OPENCODE_CONFIG_DIR env var (if set)
|
|
104
|
+
* 2. ~/.config/opencode (all platforms, including Windows)
|
|
105
|
+
*
|
|
106
|
+
* On Windows, also checks for legacy %APPDATA%\opencode path for migration.
|
|
107
|
+
*/
|
|
108
|
+
function getConfigDir() {
|
|
109
|
+
// 1. Check for explicit override via env var
|
|
110
|
+
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
111
|
+
return process.env.OPENCODE_CONFIG_DIR;
|
|
112
|
+
}
|
|
113
|
+
// 2. Use ~/.config/opencode on all platforms (including Windows)
|
|
114
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
115
|
+
return join(xdgConfig, "opencode");
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Migrates config from legacy Windows location to the new path.
|
|
119
|
+
* Moves the file if legacy exists and new doesn't.
|
|
120
|
+
* Returns true if migration was performed.
|
|
121
|
+
*/
|
|
122
|
+
function migrateLegacyWindowsConfig() {
|
|
123
|
+
if (process.platform !== "win32") {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const newPath = join(getConfigDir(), "kimicode-accounts.json");
|
|
127
|
+
const legacyPath = join(getLegacyWindowsConfigDir(), "kimicode-accounts.json");
|
|
128
|
+
// Only migrate if legacy exists and new doesn't
|
|
129
|
+
if (!existsSync(legacyPath) || existsSync(newPath)) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
// Ensure new config directory exists
|
|
134
|
+
const newConfigDir = getConfigDir();
|
|
135
|
+
mkdirSync(newConfigDir, { recursive: true });
|
|
136
|
+
// Try rename first (atomic, but fails across filesystems)
|
|
137
|
+
try {
|
|
138
|
+
renameSync(legacyPath, newPath);
|
|
139
|
+
log.info("Migrated Windows config via rename", { from: legacyPath, to: newPath });
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Fallback: copy then delete (for cross-filesystem moves)
|
|
143
|
+
copyFileSync(legacyPath, newPath);
|
|
144
|
+
unlinkSync(legacyPath);
|
|
145
|
+
log.info("Migrated Windows config via copy+delete", { from: legacyPath, to: newPath });
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
log.warn("Failed to migrate legacy Windows config, will use legacy path", {
|
|
151
|
+
legacyPath,
|
|
152
|
+
newPath,
|
|
153
|
+
error: String(error),
|
|
154
|
+
});
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Gets the storage path, migrating from legacy Windows location if needed.
|
|
160
|
+
* On Windows, attempts to move legacy config to new path for alignment.
|
|
161
|
+
*/
|
|
162
|
+
function getStoragePathWithMigration() {
|
|
163
|
+
const newPath = join(getConfigDir(), "kimicode-accounts.json");
|
|
164
|
+
// On Windows, attempt to migrate legacy config to new location
|
|
165
|
+
if (process.platform === "win32") {
|
|
166
|
+
migrateLegacyWindowsConfig();
|
|
167
|
+
// If migration failed and legacy still exists, fall back to it
|
|
168
|
+
if (!existsSync(newPath)) {
|
|
169
|
+
const legacyPath = join(getLegacyWindowsConfigDir(), "kimicode-accounts.json");
|
|
170
|
+
if (existsSync(legacyPath)) {
|
|
171
|
+
log.info("Using legacy Windows config path (migration failed)", {
|
|
172
|
+
legacyPath,
|
|
173
|
+
newPath,
|
|
174
|
+
});
|
|
175
|
+
return legacyPath;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return newPath;
|
|
180
|
+
}
|
|
181
|
+
export function getStoragePath() {
|
|
182
|
+
return getStoragePathWithMigration();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Gets the config directory path. Exported for use by other modules.
|
|
186
|
+
*/
|
|
187
|
+
export { getConfigDir };
|
|
188
|
+
const LOCK_OPTIONS = {
|
|
189
|
+
stale: 10000,
|
|
190
|
+
retries: {
|
|
191
|
+
retries: 5,
|
|
192
|
+
minTimeout: 100,
|
|
193
|
+
maxTimeout: 1000,
|
|
194
|
+
factor: 2,
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Ensures the file has secure permissions (0600) on POSIX systems.
|
|
199
|
+
* This is a best-effort operation and ignores errors on Windows/unsupported FS.
|
|
200
|
+
*/
|
|
201
|
+
async function ensureSecurePermissions(path) {
|
|
202
|
+
try {
|
|
203
|
+
await fs.chmod(path, 0o600);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Ignore errors (e.g. Windows, file doesn't exist, FS doesn't support chmod)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function ensureFileExists(path) {
|
|
210
|
+
try {
|
|
211
|
+
await fs.access(path);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
215
|
+
await fs.writeFile(path, JSON.stringify({ version: 1, accounts: [], activeIndex: 0 }, null, 2), { encoding: "utf-8", mode: 0o600 });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function withFileLock(path, fn) {
|
|
219
|
+
await ensureFileExists(path);
|
|
220
|
+
let release = null;
|
|
221
|
+
try {
|
|
222
|
+
release = await lockfile.lock(path, LOCK_OPTIONS);
|
|
223
|
+
return await fn();
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
if (release) {
|
|
227
|
+
try {
|
|
228
|
+
await release();
|
|
229
|
+
}
|
|
230
|
+
catch (unlockError) {
|
|
231
|
+
log.warn("Failed to release lock", { error: String(unlockError) });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function mergeAccountStorage(existing, incoming) {
|
|
237
|
+
const accountMap = new Map();
|
|
238
|
+
for (const acc of existing.accounts) {
|
|
239
|
+
if (acc.refreshToken) {
|
|
240
|
+
accountMap.set(acc.refreshToken, acc);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
for (const acc of incoming.accounts) {
|
|
244
|
+
if (acc.refreshToken) {
|
|
245
|
+
const existingAcc = accountMap.get(acc.refreshToken);
|
|
246
|
+
if (existingAcc) {
|
|
247
|
+
accountMap.set(acc.refreshToken, {
|
|
248
|
+
...existingAcc,
|
|
249
|
+
...acc,
|
|
250
|
+
rateLimitResetTimes: {
|
|
251
|
+
...existingAcc.rateLimitResetTimes,
|
|
252
|
+
...acc.rateLimitResetTimes,
|
|
253
|
+
},
|
|
254
|
+
lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
accountMap.set(acc.refreshToken, acc);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
version: 1,
|
|
264
|
+
accounts: Array.from(accountMap.values()),
|
|
265
|
+
activeIndex: incoming.activeIndex,
|
|
266
|
+
activeIndexByFamily: incoming.activeIndexByFamily,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export function deduplicateAccountsByEmail(accounts) {
|
|
270
|
+
const emailToNewestIndex = new Map();
|
|
271
|
+
const indicesToKeep = new Set();
|
|
272
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
273
|
+
const acc = accounts[i];
|
|
274
|
+
if (!acc)
|
|
275
|
+
continue;
|
|
276
|
+
if (!acc.email) {
|
|
277
|
+
indicesToKeep.add(i);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const existingIndex = emailToNewestIndex.get(acc.email);
|
|
281
|
+
if (existingIndex === undefined) {
|
|
282
|
+
emailToNewestIndex.set(acc.email, i);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const existing = accounts[existingIndex];
|
|
286
|
+
if (!existing) {
|
|
287
|
+
emailToNewestIndex.set(acc.email, i);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const currLastUsed = acc.lastUsed || 0;
|
|
291
|
+
const existLastUsed = existing.lastUsed || 0;
|
|
292
|
+
const currAddedAt = acc.addedAt || 0;
|
|
293
|
+
const existAddedAt = existing.addedAt || 0;
|
|
294
|
+
const isNewer = currLastUsed > existLastUsed ||
|
|
295
|
+
(currLastUsed === existLastUsed && currAddedAt > existAddedAt);
|
|
296
|
+
if (isNewer) {
|
|
297
|
+
emailToNewestIndex.set(acc.email, i);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
for (const idx of emailToNewestIndex.values()) {
|
|
301
|
+
indicesToKeep.add(idx);
|
|
302
|
+
}
|
|
303
|
+
const result = [];
|
|
304
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
305
|
+
if (indicesToKeep.has(i)) {
|
|
306
|
+
const acc = accounts[i];
|
|
307
|
+
if (acc) {
|
|
308
|
+
result.push(acc);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
export async function loadAccounts() {
|
|
315
|
+
try {
|
|
316
|
+
const path = getStoragePath();
|
|
317
|
+
await ensureSecurePermissions(path);
|
|
318
|
+
const content = await fs.readFile(path, "utf-8");
|
|
319
|
+
const data = JSON.parse(content);
|
|
320
|
+
if (!Array.isArray(data.accounts)) {
|
|
321
|
+
log.warn("Invalid storage format, ignoring");
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
if (data.version !== 1) {
|
|
325
|
+
log.warn("Unknown storage version, ignoring", {
|
|
326
|
+
version: data.version,
|
|
327
|
+
});
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const validAccounts = data.accounts.filter((a) => {
|
|
331
|
+
return (!!a &&
|
|
332
|
+
typeof a === "object" &&
|
|
333
|
+
typeof a.refreshToken === "string");
|
|
334
|
+
});
|
|
335
|
+
const deduplicatedAccounts = deduplicateAccountsByEmail(validAccounts);
|
|
336
|
+
let activeIndex = typeof data.activeIndex === "number" &&
|
|
337
|
+
Number.isFinite(data.activeIndex)
|
|
338
|
+
? data.activeIndex
|
|
339
|
+
: 0;
|
|
340
|
+
if (deduplicatedAccounts.length > 0) {
|
|
341
|
+
activeIndex = Math.min(activeIndex, deduplicatedAccounts.length - 1);
|
|
342
|
+
activeIndex = Math.max(activeIndex, 0);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
activeIndex = 0;
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
version: 1,
|
|
349
|
+
accounts: deduplicatedAccounts,
|
|
350
|
+
activeIndex,
|
|
351
|
+
activeIndexByFamily: data.activeIndexByFamily,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
const code = error.code;
|
|
356
|
+
if (code === "ENOENT") {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
log.error("Failed to load account storage", { error: String(error) });
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
export async function saveAccounts(storage) {
|
|
364
|
+
const path = getStoragePath();
|
|
365
|
+
const configDir = dirname(path);
|
|
366
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
367
|
+
await ensureGitignore(configDir);
|
|
368
|
+
await withFileLock(path, async () => {
|
|
369
|
+
const existing = await loadAccountsUnsafe();
|
|
370
|
+
const merged = existing ? mergeAccountStorage(existing, storage) : storage;
|
|
371
|
+
const tempPath = `${path}.${randomBytes(6).toString("hex")}.tmp`;
|
|
372
|
+
const content = JSON.stringify(merged, null, 2);
|
|
373
|
+
try {
|
|
374
|
+
await fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 });
|
|
375
|
+
await fs.rename(tempPath, path);
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
try {
|
|
379
|
+
await fs.unlink(tempPath);
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
// Ignore cleanup errors (file may not exist)
|
|
383
|
+
}
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Save accounts storage by replacing the entire file (no merge).
|
|
390
|
+
* Use this for destructive operations like delete where we need to
|
|
391
|
+
* remove accounts that would otherwise be merged back from existing storage.
|
|
392
|
+
*/
|
|
393
|
+
export async function saveAccountsReplace(storage) {
|
|
394
|
+
const path = getStoragePath();
|
|
395
|
+
const configDir = dirname(path);
|
|
396
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
397
|
+
await ensureGitignore(configDir);
|
|
398
|
+
await withFileLock(path, async () => {
|
|
399
|
+
const tempPath = `${path}.${randomBytes(6).toString("hex")}.tmp`;
|
|
400
|
+
const content = JSON.stringify(storage, null, 2);
|
|
401
|
+
try {
|
|
402
|
+
await fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 });
|
|
403
|
+
await fs.rename(tempPath, path);
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
try {
|
|
407
|
+
await fs.unlink(tempPath);
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// Ignore cleanup errors
|
|
411
|
+
}
|
|
412
|
+
throw error;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
async function loadAccountsUnsafe() {
|
|
417
|
+
try {
|
|
418
|
+
const path = getStoragePath();
|
|
419
|
+
await ensureSecurePermissions(path);
|
|
420
|
+
const content = await fs.readFile(path, "utf-8");
|
|
421
|
+
const parsed = JSON.parse(content);
|
|
422
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.accounts)) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
...parsed,
|
|
427
|
+
accounts: deduplicateAccountsByEmail(parsed.accounts),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
const code = error.code;
|
|
432
|
+
if (code === "ENOENT") {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
export async function clearAccounts() {
|
|
439
|
+
try {
|
|
440
|
+
const path = getStoragePath();
|
|
441
|
+
await fs.unlink(path);
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
const code = error.code;
|
|
445
|
+
if (code !== "ENOENT") {
|
|
446
|
+
log.error("Failed to clear account storage", { error: String(error) });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/plugin/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { OAuthAuthDetails, PluginClient } from "./types";
|
|
2
|
+
export declare class KimiTokenRefreshError extends Error {
|
|
3
|
+
code?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
status: number;
|
|
6
|
+
statusText: string;
|
|
7
|
+
constructor(options: {
|
|
8
|
+
message: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
status: number;
|
|
12
|
+
statusText: string;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Refreshes a Kimi OAuth access token using the refresh_token grant.
|
|
17
|
+
*/
|
|
18
|
+
export declare function refreshAccessToken(auth: OAuthAuthDetails, _client: PluginClient, _providerId: string): Promise<OAuthAuthDetails | undefined>;
|
|
19
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/plugin/token.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAsC7D,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;gBAEN,OAAO,EAAE;QACnB,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;KACnB;CAQF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAmEvC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { KIMI_CLIENT_ID, KIMI_TOKEN_ENDPOINT, getKimiOAuthHeaders } from "../constants";
|
|
2
|
+
import { calculateTokenExpiry } from "./auth";
|
|
3
|
+
import { clearCachedAuth, storeCachedAuth } from "./cache";
|
|
4
|
+
import { createLogger } from "./logger";
|
|
5
|
+
const log = createLogger("token");
|
|
6
|
+
function parseOAuthErrorPayload(text) {
|
|
7
|
+
if (!text)
|
|
8
|
+
return {};
|
|
9
|
+
try {
|
|
10
|
+
const payload = JSON.parse(text);
|
|
11
|
+
if (!payload || typeof payload !== "object")
|
|
12
|
+
return { description: text };
|
|
13
|
+
let code;
|
|
14
|
+
if (typeof payload.error === "string") {
|
|
15
|
+
code = payload.error;
|
|
16
|
+
}
|
|
17
|
+
else if (payload.error && typeof payload.error === "object") {
|
|
18
|
+
code = payload.error.status ?? payload.error.code;
|
|
19
|
+
if (!payload.error_description && payload.error.message) {
|
|
20
|
+
return { code, description: payload.error.message };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const description = payload.error_description;
|
|
24
|
+
if (description)
|
|
25
|
+
return { code, description };
|
|
26
|
+
if (payload.error && typeof payload.error === "object" && payload.error.message) {
|
|
27
|
+
return { code, description: payload.error.message };
|
|
28
|
+
}
|
|
29
|
+
return { code };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { description: text };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class KimiTokenRefreshError extends Error {
|
|
36
|
+
code;
|
|
37
|
+
description;
|
|
38
|
+
status;
|
|
39
|
+
statusText;
|
|
40
|
+
constructor(options) {
|
|
41
|
+
super(options.message);
|
|
42
|
+
this.name = "KimiTokenRefreshError";
|
|
43
|
+
this.code = options.code;
|
|
44
|
+
this.description = options.description;
|
|
45
|
+
this.status = options.status;
|
|
46
|
+
this.statusText = options.statusText;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Refreshes a Kimi OAuth access token using the refresh_token grant.
|
|
51
|
+
*/
|
|
52
|
+
export async function refreshAccessToken(auth, _client, _providerId) {
|
|
53
|
+
const refreshToken = auth.refresh;
|
|
54
|
+
if (!refreshToken)
|
|
55
|
+
return undefined;
|
|
56
|
+
try {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
const response = await fetch(KIMI_TOKEN_ENDPOINT, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: {
|
|
61
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
62
|
+
...getKimiOAuthHeaders(),
|
|
63
|
+
},
|
|
64
|
+
body: new URLSearchParams({
|
|
65
|
+
grant_type: "refresh_token",
|
|
66
|
+
refresh_token: refreshToken,
|
|
67
|
+
client_id: KIMI_CLIENT_ID,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
let errorText;
|
|
72
|
+
try {
|
|
73
|
+
errorText = await response.text();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
errorText = undefined;
|
|
77
|
+
}
|
|
78
|
+
const { code, description } = parseOAuthErrorPayload(errorText);
|
|
79
|
+
const details = [code, description ?? errorText].filter(Boolean).join(": ");
|
|
80
|
+
const baseMessage = `Kimi token refresh failed (${response.status} ${response.statusText})`;
|
|
81
|
+
const message = details ? `${baseMessage} - ${details}` : baseMessage;
|
|
82
|
+
log.warn("Token refresh failed", { status: response.status, code, details });
|
|
83
|
+
if (code === "invalid_grant" || response.status === 401 || response.status === 403) {
|
|
84
|
+
log.warn("Kimi revoked the stored refresh token - reauthentication required");
|
|
85
|
+
clearCachedAuth(auth.refresh);
|
|
86
|
+
}
|
|
87
|
+
throw new KimiTokenRefreshError({
|
|
88
|
+
message,
|
|
89
|
+
code,
|
|
90
|
+
description: description ?? errorText,
|
|
91
|
+
status: response.status,
|
|
92
|
+
statusText: response.statusText,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const payload = (await response.json());
|
|
96
|
+
const updatedAuth = {
|
|
97
|
+
...auth,
|
|
98
|
+
access: payload.access_token,
|
|
99
|
+
expires: calculateTokenExpiry(startTime, payload.expires_in),
|
|
100
|
+
refresh: payload.refresh_token ?? refreshToken,
|
|
101
|
+
};
|
|
102
|
+
storeCachedAuth(updatedAuth);
|
|
103
|
+
return updatedAuth;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof KimiTokenRefreshError)
|
|
107
|
+
throw error;
|
|
108
|
+
log.error("Unexpected token refresh error", { error: String(error) });
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/plugin/token.ts"],"names":[],"mappings":"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"}
|