opencode-qwen-oauth 2.3.1 → 2.4.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/README.md +52 -60
- package/dist/api-key-exchange.js +1 -1
- package/dist/api-key-exchange.js.map +1 -1
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -443
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.middleware.d.ts +10 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +102 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/rate-limit.middleware.d.ts +10 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +22 -0
- package/dist/middleware/rate-limit.middleware.js.map +1 -0
- package/dist/middleware/retry.middleware.d.ts +11 -0
- package/dist/middleware/retry.middleware.d.ts.map +1 -0
- package/dist/middleware/retry.middleware.js +43 -0
- package/dist/middleware/retry.middleware.js.map +1 -0
- package/dist/repositories/credential.repository.d.ts +13 -0
- package/dist/repositories/credential.repository.d.ts.map +1 -0
- package/dist/repositories/credential.repository.js +65 -0
- package/dist/repositories/credential.repository.js.map +1 -0
- package/dist/services/token.service.d.ts +20 -0
- package/dist/services/token.service.d.ts.map +1 -0
- package/dist/services/token.service.js +106 -0
- package/dist/services/token.service.js.map +1 -0
- package/dist/strategies/oauth.strategy.d.ts +9 -0
- package/dist/strategies/oauth.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth.strategy.js +249 -0
- package/dist/strategies/oauth.strategy.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mutex.d.ts +16 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +54 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/pkce.d.ts +8 -0
- package/dist/utils/pkce.d.ts.map +1 -0
- package/dist/utils/pkce.js +17 -0
- package/dist/utils/pkce.js.map +1 -0
- package/package.json +4 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication middleware for fetch requests
|
|
3
|
+
* Handles token injection, retry logic, and error recovery
|
|
4
|
+
*/
|
|
5
|
+
export interface AuthMiddlewareConfig {
|
|
6
|
+
platform: string;
|
|
7
|
+
arch: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function createAuthMiddleware(config: AuthMiddlewareConfig): (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
10
|
+
//# sourceMappingURL=auth.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,IAG/B,OAAO,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,OAAO,WAAW,KAAG,OAAO,CAAC,QAAQ,CAAC,CA2GtG"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication middleware for fetch requests
|
|
3
|
+
* Handles token injection, retry logic, and error recovery
|
|
4
|
+
*/
|
|
5
|
+
import { tokenService } from "../services/token.service.js";
|
|
6
|
+
import { requestQueue } from "./rate-limit.middleware.js";
|
|
7
|
+
import { credentialRepository } from "../repositories/credential.repository.js";
|
|
8
|
+
import { warnLog, infoLog } from "../utils/logger.js";
|
|
9
|
+
import { refreshAccessToken } from "../strategies/oauth.strategy.js";
|
|
10
|
+
import { Mutex } from "../utils/mutex.js";
|
|
11
|
+
const QWEN_CODE_VERSION = "0.10.3";
|
|
12
|
+
const tokenRefreshMutex = new Mutex();
|
|
13
|
+
export function createAuthMiddleware(config) {
|
|
14
|
+
const userAgent = `QwenCode/${QWEN_CODE_VERSION} (${config.platform}; ${config.arch})`;
|
|
15
|
+
return async function authFetch(input, init) {
|
|
16
|
+
const auth = await getAuthWithRefresh();
|
|
17
|
+
if (!auth) {
|
|
18
|
+
return createErrorResponse(401, "No authentication available");
|
|
19
|
+
}
|
|
20
|
+
return requestQueue.enqueue(async () => {
|
|
21
|
+
let currentAuth = auth;
|
|
22
|
+
for (let attempt = 0; attempt <= 2; attempt++) {
|
|
23
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
24
|
+
const headers = new Headers(init?.headers);
|
|
25
|
+
const tokenToUse = currentAuth.apiKey || currentAuth.access;
|
|
26
|
+
if (tokenToUse) {
|
|
27
|
+
headers.set("Authorization", `Bearer ${tokenToUse}`);
|
|
28
|
+
headers.set("User-Agent", userAgent);
|
|
29
|
+
headers.set("X-DashScope-CacheControl", "enable");
|
|
30
|
+
headers.set("X-DashScope-UserAgent", userAgent);
|
|
31
|
+
headers.set("X-DashScope-AuthType", "qwen-oauth");
|
|
32
|
+
}
|
|
33
|
+
const response = await fetch(url, { ...init, headers });
|
|
34
|
+
if (response.status === 429) {
|
|
35
|
+
const retryAfter = response.headers.get("Retry-After") || "60";
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, parseInt(retryAfter, 10) * 1000));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (response.status === 401 || response.status === 403) {
|
|
40
|
+
const refreshedAuth = await handleAuthFailure(currentAuth);
|
|
41
|
+
if (refreshedAuth) {
|
|
42
|
+
currentAuth = refreshedAuth;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
return createErrorResponse(401, "Authentication failed. Please re-authenticate.");
|
|
46
|
+
}
|
|
47
|
+
return response;
|
|
48
|
+
}
|
|
49
|
+
return createErrorResponse(500, "Maximum retry attempts exceeded");
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
async function getAuthWithRefresh() {
|
|
53
|
+
try {
|
|
54
|
+
return await tokenService.refreshIfNeeded();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
warnLog("Failed to refresh token", { error: String(error) });
|
|
58
|
+
const fileAuth = tokenService.loadFromFile();
|
|
59
|
+
if (fileAuth) {
|
|
60
|
+
tokenService.setCachedAuth(fileAuth);
|
|
61
|
+
return fileAuth;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function handleAuthFailure(currentAuth) {
|
|
67
|
+
warnLog("Received 401/403, attempting token refresh");
|
|
68
|
+
return tokenRefreshMutex.runExclusive(async () => {
|
|
69
|
+
if (!currentAuth.refresh) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const result = await refreshAccessToken(currentAuth.refresh);
|
|
73
|
+
if (result.success && result.access_token) {
|
|
74
|
+
const expiresIn = result.expires_in || 0;
|
|
75
|
+
const newExpires = expiresIn > 0 ? Date.now() + expiresIn * 1000 : Date.now() + 3600 * 1000;
|
|
76
|
+
const newAuth = {
|
|
77
|
+
type: "oauth",
|
|
78
|
+
refresh: result.refresh_token || currentAuth.refresh,
|
|
79
|
+
access: result.access_token,
|
|
80
|
+
expires: newExpires,
|
|
81
|
+
apiKey: result.api_key || currentAuth.apiKey,
|
|
82
|
+
};
|
|
83
|
+
tokenService.setCachedAuth(newAuth);
|
|
84
|
+
credentialRepository.save({
|
|
85
|
+
accessToken: newAuth.access,
|
|
86
|
+
refreshToken: newAuth.refresh,
|
|
87
|
+
expiryDate: newExpires,
|
|
88
|
+
tokenType: "Bearer",
|
|
89
|
+
});
|
|
90
|
+
infoLog("Token refreshed after 401/403");
|
|
91
|
+
return newAuth;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function createErrorResponse(status, message) {
|
|
97
|
+
return new Response(JSON.stringify({
|
|
98
|
+
error: { code: "auth_error", message, type: "auth_error" },
|
|
99
|
+
}), { status, headers: { "Content-Type": "application/json" } });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=auth.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class RequestQueue {
|
|
2
|
+
private lastRequestTime;
|
|
3
|
+
private readonly MIN_INTERVAL;
|
|
4
|
+
private readonly JITTER_MIN;
|
|
5
|
+
private readonly JITTER_MAX;
|
|
6
|
+
private getJitter;
|
|
7
|
+
enqueue<T>(fn: () => Promise<T>): Promise<T>;
|
|
8
|
+
}
|
|
9
|
+
export declare const requestQueue: RequestQueue;
|
|
10
|
+
//# sourceMappingURL=rate-limit.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.middleware.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAY;IACvB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAO;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IAEnC,OAAO,CAAC,SAAS;IAIX,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAanD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class RequestQueue {
|
|
2
|
+
lastRequestTime = 0;
|
|
3
|
+
MIN_INTERVAL = 1000;
|
|
4
|
+
JITTER_MIN = 500;
|
|
5
|
+
JITTER_MAX = 1500;
|
|
6
|
+
getJitter() {
|
|
7
|
+
return Math.random() * (this.JITTER_MAX - this.JITTER_MIN) + this.JITTER_MIN;
|
|
8
|
+
}
|
|
9
|
+
async enqueue(fn) {
|
|
10
|
+
const elapsed = Date.now() - this.lastRequestTime;
|
|
11
|
+
const baseWait = Math.max(0, this.MIN_INTERVAL - elapsed);
|
|
12
|
+
const jitter = this.getJitter();
|
|
13
|
+
const waitTime = baseWait + jitter;
|
|
14
|
+
if (waitTime > 0) {
|
|
15
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
16
|
+
}
|
|
17
|
+
this.lastRequestTime = Date.now();
|
|
18
|
+
return fn();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const requestQueue = new RequestQueue();
|
|
22
|
+
//# sourceMappingURL=rate-limit.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.middleware.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.middleware.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,YAAY;IACf,eAAe,GAAG,CAAC,CAAC;IACX,YAAY,GAAG,IAAI,CAAC;IACpB,UAAU,GAAG,GAAG,CAAC;IACjB,UAAU,GAAG,IAAI,CAAC;IAE3B,SAAS;QACf,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;IAC/E,CAAC;IAED,KAAK,CAAC,OAAO,CAAI,EAAoB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;QAEnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAClC,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;CACF;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry middleware with exponential backoff
|
|
3
|
+
*/
|
|
4
|
+
export interface RetryConfig {
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
baseDelay?: number;
|
|
7
|
+
maxDelay?: number;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function fetchWithRetry(url: string, init: RequestInit, config?: RetryConfig): Promise<Response>;
|
|
11
|
+
//# sourceMappingURL=retry.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/retry.middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,QAAQ,CAAC,CAqCnB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry middleware with exponential backoff
|
|
3
|
+
*/
|
|
4
|
+
import { debugLog, warnLog } from "../utils/logger.js";
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
maxRetries: 3,
|
|
7
|
+
baseDelay: 1000,
|
|
8
|
+
maxDelay: 30000,
|
|
9
|
+
timeout: 30000,
|
|
10
|
+
};
|
|
11
|
+
export async function fetchWithRetry(url, init, config = {}) {
|
|
12
|
+
const { maxRetries, baseDelay, maxDelay, timeout } = { ...DEFAULT_CONFIG, ...config };
|
|
13
|
+
let lastError = null;
|
|
14
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
15
|
+
try {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
18
|
+
const response = await fetch(url, {
|
|
19
|
+
...init,
|
|
20
|
+
signal: controller.signal,
|
|
21
|
+
});
|
|
22
|
+
clearTimeout(timeoutId);
|
|
23
|
+
if (response.status === 429) {
|
|
24
|
+
const retryAfter = response.headers.get("Retry-After") || "60";
|
|
25
|
+
const waitTimeMs = parseInt(retryAfter, 10) * 1000;
|
|
26
|
+
warnLog("Rate limited (429), waiting and retrying", { retryAfter, waitTimeMs });
|
|
27
|
+
await new Promise((resolve) => setTimeout(resolve, waitTimeMs));
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
34
|
+
debugLog(`Request failed (attempt ${attempt + 1}/${maxRetries + 1})`, { error: lastError.message });
|
|
35
|
+
if (attempt < maxRetries) {
|
|
36
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
37
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw lastError || new Error("Request failed after all retries");
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=retry.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.middleware.js","sourceRoot":"","sources":["../../src/middleware/retry.middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AASvD,MAAM,cAAc,GAA0B;IAC5C,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,IAAiB,EACjB,SAAsB,EAAE;IAExB,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IACtF,IAAI,SAAS,GAAiB,IAAI,CAAC;IAEnC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;YAEhE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,GAAG,IAAI;gBACP,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,YAAY,CAAC,SAAS,CAAC,CAAC;YAExB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC;gBAC/D,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;gBACnD,OAAO,CAAC,0CAA0C,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;gBAChF,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,QAAQ,CAAC,2BAA2B,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;YAEpG,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACnE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential storage repository
|
|
3
|
+
* Handles file system operations for OAuth credentials
|
|
4
|
+
*/
|
|
5
|
+
import { StoredCredentials } from "../types.js";
|
|
6
|
+
export declare class CredentialRepository {
|
|
7
|
+
private ensureDirectory;
|
|
8
|
+
save(credentials: StoredCredentials): boolean;
|
|
9
|
+
load(): StoredCredentials | null;
|
|
10
|
+
clear(): boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const credentialRepository: CredentialRepository;
|
|
13
|
+
//# sourceMappingURL=credential.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential.repository.d.ts","sourceRoot":"","sources":["../../src/repositories/credential.repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKhD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,eAAe;IAOvB,IAAI,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO;IAY7C,IAAI,IAAI,iBAAiB,GAAG,IAAI;IA0BhC,KAAK,IAAI,OAAO;CAWjB;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential storage repository
|
|
3
|
+
* Handles file system operations for OAuth credentials
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { debugLog, warnLog } from "../utils/logger.js";
|
|
9
|
+
const CREDENTIALS_PATH = join(homedir(), ".qwen", "oauth_creds.json");
|
|
10
|
+
export class CredentialRepository {
|
|
11
|
+
ensureDirectory() {
|
|
12
|
+
const dir = join(homedir(), ".qwen");
|
|
13
|
+
if (!existsSync(dir)) {
|
|
14
|
+
mkdirSync(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
save(credentials) {
|
|
18
|
+
try {
|
|
19
|
+
this.ensureDirectory();
|
|
20
|
+
writeFileSync(CREDENTIALS_PATH, JSON.stringify(credentials, null, 2));
|
|
21
|
+
debugLog("Credentials saved", { path: CREDENTIALS_PATH });
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
warnLog("Failed to save credentials", { error: String(error) });
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
load() {
|
|
30
|
+
try {
|
|
31
|
+
if (!existsSync(CREDENTIALS_PATH)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const data = readFileSync(CREDENTIALS_PATH, "utf-8");
|
|
35
|
+
const credentials = JSON.parse(data);
|
|
36
|
+
if (!credentials.accessToken || !credentials.refreshToken) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
debugLog("Credentials loaded", {
|
|
40
|
+
hasAccess: !!credentials.accessToken,
|
|
41
|
+
hasRefresh: !!credentials.refreshToken,
|
|
42
|
+
expiryDate: credentials.expiryDate,
|
|
43
|
+
});
|
|
44
|
+
return credentials;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
debugLog("Failed to load credentials", { error: String(error) });
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
clear() {
|
|
52
|
+
try {
|
|
53
|
+
if (existsSync(CREDENTIALS_PATH)) {
|
|
54
|
+
writeFileSync(CREDENTIALS_PATH, JSON.stringify({}));
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
warnLog("Failed to clear credentials", { error: String(error) });
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export const credentialRepository = new CredentialRepository();
|
|
65
|
+
//# sourceMappingURL=credential.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential.repository.js","sourceRoot":"","sources":["../../src/repositories/credential.repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAEtE,MAAM,OAAO,oBAAoB;IACvB,eAAe;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAA8B;QACjC,IAAI,CAAC;YACH,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACtE,QAAQ,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,IAAI,GAAG,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsB,CAAC;YAE1D,IAAI,CAAC,WAAW,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;gBAC1D,OAAO,IAAI,CAAC;YACd,CAAC;YAED,QAAQ,CAAC,oBAAoB,EAAE;gBAC7B,SAAS,EAAE,CAAC,CAAC,WAAW,CAAC,WAAW;gBACpC,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,YAAY;gBACtC,UAAU,EAAE,WAAW,CAAC,UAAU;aACnC,CAAC,CAAC;YAEH,OAAO,WAAW,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACjC,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;YACtD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACjE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token management service
|
|
3
|
+
* Handles token refresh, validation, and caching
|
|
4
|
+
*/
|
|
5
|
+
import { OAuthAuthDetails } from "../types.js";
|
|
6
|
+
export declare class TokenService {
|
|
7
|
+
private cachedToken;
|
|
8
|
+
private cachedTokenExpiry;
|
|
9
|
+
private lastRefreshTime;
|
|
10
|
+
private cachedAuth;
|
|
11
|
+
private mutex;
|
|
12
|
+
setCachedAuth(auth: OAuthAuthDetails): void;
|
|
13
|
+
getCachedAuth(): OAuthAuthDetails | null;
|
|
14
|
+
refreshIfNeeded(): Promise<OAuthAuthDetails>;
|
|
15
|
+
private saveCredentials;
|
|
16
|
+
loadFromFile(): OAuthAuthDetails | null;
|
|
17
|
+
reset(): void;
|
|
18
|
+
}
|
|
19
|
+
export declare const tokenService: TokenService;
|
|
20
|
+
//# sourceMappingURL=token.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.service.d.ts","sourceRoot":"","sources":["../../src/services/token.service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,gBAAgB,EAAoC,MAAM,aAAa,CAAC;AAMjF,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,KAAK,CAAe;IAE5B,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAI3C,aAAa,IAAI,gBAAgB,GAAG,IAAI;IAIlC,eAAe,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAwElD,OAAO,CAAC,eAAe;IASvB,YAAY,IAAI,gBAAgB,GAAG,IAAI;IAYvC,KAAK,IAAI,IAAI;CAMd;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token management service
|
|
3
|
+
* Handles token refresh, validation, and caching
|
|
4
|
+
*/
|
|
5
|
+
import { Mutex } from "../utils/mutex.js";
|
|
6
|
+
import { refreshAccessToken as oauthRefreshToken } from "../strategies/oauth.strategy.js";
|
|
7
|
+
import { credentialRepository } from "../repositories/credential.repository.js";
|
|
8
|
+
import { debugLog, infoLog, warnLog } from "../utils/logger.js";
|
|
9
|
+
const TOKEN_CACHE_DURATION = 5 * 60 * 1000;
|
|
10
|
+
const REFRESH_BEFORE_EXPIRY_MS = 5 * 60 * 1000;
|
|
11
|
+
export class TokenService {
|
|
12
|
+
cachedToken = null;
|
|
13
|
+
cachedTokenExpiry = 0;
|
|
14
|
+
lastRefreshTime = 0;
|
|
15
|
+
cachedAuth = null;
|
|
16
|
+
mutex = new Mutex();
|
|
17
|
+
setCachedAuth(auth) {
|
|
18
|
+
this.cachedAuth = auth;
|
|
19
|
+
}
|
|
20
|
+
getCachedAuth() {
|
|
21
|
+
return this.cachedAuth;
|
|
22
|
+
}
|
|
23
|
+
async refreshIfNeeded() {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
if (this.cachedToken && now < this.cachedTokenExpiry && now - this.lastRefreshTime < TOKEN_CACHE_DURATION) {
|
|
26
|
+
if (this.cachedAuth) {
|
|
27
|
+
return this.cachedAuth;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!this.cachedAuth) {
|
|
31
|
+
throw new Error("No authentication available");
|
|
32
|
+
}
|
|
33
|
+
const expiresAt = this.cachedAuth.expires || 0;
|
|
34
|
+
const timeUntilExpiry = expiresAt - now;
|
|
35
|
+
const hasValidExpiry = expiresAt > now;
|
|
36
|
+
const shouldRefresh = !this.cachedAuth.access ||
|
|
37
|
+
!hasValidExpiry ||
|
|
38
|
+
timeUntilExpiry < REFRESH_BEFORE_EXPIRY_MS;
|
|
39
|
+
debugLog("Token refresh check", {
|
|
40
|
+
hasAccess: !!this.cachedAuth.access,
|
|
41
|
+
expiresAt: expiresAt > 0 ? new Date(expiresAt).toISOString() : "not set",
|
|
42
|
+
timeUntilExpiry: timeUntilExpiry > 0 ? Math.round(timeUntilExpiry / 1000) + "s" : "EXPIRED",
|
|
43
|
+
shouldRefresh,
|
|
44
|
+
});
|
|
45
|
+
if (!shouldRefresh && this.cachedToken) {
|
|
46
|
+
debugLog("Token still valid, no refresh needed");
|
|
47
|
+
return this.cachedAuth;
|
|
48
|
+
}
|
|
49
|
+
infoLog("Token refresh needed", {
|
|
50
|
+
reason: !this.cachedAuth.access ? "no access token" : !hasValidExpiry ? "token expired" : "token expires soon",
|
|
51
|
+
});
|
|
52
|
+
return this.mutex.runExclusive(async () => {
|
|
53
|
+
const currentAuth = this.cachedAuth;
|
|
54
|
+
if (!currentAuth || !currentAuth.refresh) {
|
|
55
|
+
throw new Error("No refresh token available");
|
|
56
|
+
}
|
|
57
|
+
const result = await oauthRefreshToken(currentAuth.refresh);
|
|
58
|
+
if (result.success && result.access_token) {
|
|
59
|
+
const expiresIn = result.expires_in || 0;
|
|
60
|
+
const newExpires = expiresIn > 0 ? Date.now() + expiresIn * 1000 : Date.now() + 3600 * 1000;
|
|
61
|
+
const newAuth = {
|
|
62
|
+
type: "oauth",
|
|
63
|
+
refresh: result.refresh_token || currentAuth.refresh,
|
|
64
|
+
access: result.access_token,
|
|
65
|
+
expires: newExpires,
|
|
66
|
+
apiKey: result.api_key || currentAuth.apiKey,
|
|
67
|
+
};
|
|
68
|
+
this.cachedAuth = newAuth;
|
|
69
|
+
this.cachedToken = newAuth.access;
|
|
70
|
+
this.cachedTokenExpiry = newExpires;
|
|
71
|
+
this.lastRefreshTime = Date.now();
|
|
72
|
+
this.saveCredentials(newAuth);
|
|
73
|
+
return newAuth;
|
|
74
|
+
}
|
|
75
|
+
warnLog("Token refresh failed", { error: result.error });
|
|
76
|
+
throw new Error(result.error || "Token refresh failed");
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
saveCredentials(auth) {
|
|
80
|
+
credentialRepository.save({
|
|
81
|
+
accessToken: auth.access,
|
|
82
|
+
refreshToken: auth.refresh,
|
|
83
|
+
expiryDate: auth.expires || Date.now() + 3600 * 1000,
|
|
84
|
+
tokenType: "Bearer",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
loadFromFile() {
|
|
88
|
+
const stored = credentialRepository.load();
|
|
89
|
+
if (!stored)
|
|
90
|
+
return null;
|
|
91
|
+
return {
|
|
92
|
+
type: "oauth",
|
|
93
|
+
access: stored.accessToken,
|
|
94
|
+
refresh: stored.refreshToken,
|
|
95
|
+
expires: stored.expiryDate,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
reset() {
|
|
99
|
+
this.cachedToken = null;
|
|
100
|
+
this.cachedTokenExpiry = 0;
|
|
101
|
+
this.lastRefreshTime = 0;
|
|
102
|
+
this.cachedAuth = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export const tokenService = new TokenService();
|
|
106
|
+
//# sourceMappingURL=token.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.service.js","sourceRoot":"","sources":["../../src/services/token.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth Device Flow strategy
|
|
3
|
+
* Implements OAuth 2.0 Device Authorization Grant (RFC 8628)
|
|
4
|
+
*/
|
|
5
|
+
import { DeviceAuthorization, TokenResponse } from "../types.js";
|
|
6
|
+
export declare function authorizeDevice(): Promise<DeviceAuthorization>;
|
|
7
|
+
export declare function pollForToken(deviceCode: string, codeVerifier: string, intervalSeconds: number, expiresIn: number): Promise<TokenResponse>;
|
|
8
|
+
export declare function refreshAccessToken(refreshToken: string): Promise<TokenResponse>;
|
|
9
|
+
//# sourceMappingURL=oauth.strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.strategy.d.ts","sourceRoot":"","sources":["../../src/strategies/oauth.strategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjE,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,CAAC,CA8DpE;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CAsIxB;AAED,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0FrF"}
|