opencode-qwen-oauth 2.3.0 → 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.
Files changed (51) hide show
  1. package/README.md +83 -73
  2. package/bin/install.js +1 -1
  3. package/dist/api-key-exchange.js +1 -1
  4. package/dist/api-key-exchange.js.map +1 -1
  5. package/dist/browser.js +1 -1
  6. package/dist/browser.js.map +1 -1
  7. package/dist/index.d.ts +1 -4
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +50 -443
  10. package/dist/index.js.map +1 -1
  11. package/dist/middleware/auth.middleware.d.ts +10 -0
  12. package/dist/middleware/auth.middleware.d.ts.map +1 -0
  13. package/dist/middleware/auth.middleware.js +102 -0
  14. package/dist/middleware/auth.middleware.js.map +1 -0
  15. package/dist/middleware/rate-limit.middleware.d.ts +10 -0
  16. package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
  17. package/dist/middleware/rate-limit.middleware.js +22 -0
  18. package/dist/middleware/rate-limit.middleware.js.map +1 -0
  19. package/dist/middleware/retry.middleware.d.ts +11 -0
  20. package/dist/middleware/retry.middleware.d.ts.map +1 -0
  21. package/dist/middleware/retry.middleware.js +43 -0
  22. package/dist/middleware/retry.middleware.js.map +1 -0
  23. package/dist/repositories/credential.repository.d.ts +13 -0
  24. package/dist/repositories/credential.repository.d.ts.map +1 -0
  25. package/dist/repositories/credential.repository.js +65 -0
  26. package/dist/repositories/credential.repository.js.map +1 -0
  27. package/dist/services/token.service.d.ts +20 -0
  28. package/dist/services/token.service.d.ts.map +1 -0
  29. package/dist/services/token.service.js +106 -0
  30. package/dist/services/token.service.js.map +1 -0
  31. package/dist/strategies/oauth.strategy.d.ts +9 -0
  32. package/dist/strategies/oauth.strategy.d.ts.map +1 -0
  33. package/dist/strategies/oauth.strategy.js +249 -0
  34. package/dist/strategies/oauth.strategy.js.map +1 -0
  35. package/dist/types.d.ts +38 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +5 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils/logger.d.ts +24 -0
  40. package/dist/utils/logger.d.ts.map +1 -0
  41. package/dist/utils/logger.js +32 -0
  42. package/dist/utils/logger.js.map +1 -0
  43. package/dist/utils/mutex.d.ts +16 -0
  44. package/dist/utils/mutex.d.ts.map +1 -0
  45. package/dist/utils/mutex.js +54 -0
  46. package/dist/utils/mutex.js.map +1 -0
  47. package/dist/utils/pkce.d.ts +8 -0
  48. package/dist/utils/pkce.d.ts.map +1 -0
  49. package/dist/utils/pkce.js +17 -0
  50. package/dist/utils/pkce.js.map +1 -0
  51. package/package.json +4 -3
@@ -0,0 +1,249 @@
1
+ /**
2
+ * OAuth Device Flow strategy
3
+ * Implements OAuth 2.0 Device Authorization Grant (RFC 8628)
4
+ */
5
+ import { QWEN_OAUTH_BASE_URL, QWEN_DEVICE_CODE_ENDPOINT, QWEN_TOKEN_ENDPOINT, QWEN_CLIENT_ID, QWEN_SCOPES, } from "../constants.js";
6
+ import { createPkcePair } from "../utils/pkce.js";
7
+ import { fetchWithRetry } from "../middleware/retry.middleware.js";
8
+ import { getConfig } from "../config.js";
9
+ import { validateDeviceCode, validateUserCode, validateToken, validateExpiresIn, validateInterval, validateQwenUrl, validateOAuthError, } from "../validation.js";
10
+ import { debugLog, warnLog, infoLog } from "../utils/logger.js";
11
+ const activePollingOperations = new Set();
12
+ export async function authorizeDevice() {
13
+ const config = getConfig();
14
+ const { verifier, challenge } = createPkcePair();
15
+ const params = new URLSearchParams({
16
+ client_id: QWEN_CLIENT_ID,
17
+ scope: QWEN_SCOPES.join(" "),
18
+ code_challenge: challenge,
19
+ code_challenge_method: "S256",
20
+ });
21
+ try {
22
+ const response = await fetchWithRetry(`${QWEN_OAUTH_BASE_URL}${QWEN_DEVICE_CODE_ENDPOINT}`, {
23
+ method: "POST",
24
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
25
+ body: params.toString(),
26
+ }, {
27
+ maxRetries: config.maxRetries,
28
+ baseDelay: config.baseRetryDelay,
29
+ maxDelay: config.maxRetryDelay,
30
+ timeout: config.timeout,
31
+ });
32
+ const data = (await response.json());
33
+ validateDeviceCode(String(data.device_code));
34
+ validateUserCode(String(data.user_code));
35
+ const expiresIn = validateExpiresIn(typeof data.expires_in === "number" ? data.expires_in : undefined, 300);
36
+ const interval = validateInterval(typeof data.interval === "number" ? data.interval : undefined);
37
+ if (!validateQwenUrl(String(data.verification_uri))) {
38
+ throw new Error("Invalid verificationURI received from server");
39
+ }
40
+ debugLog("Device authorization successful", {
41
+ user_code: String(data.user_code),
42
+ expires_in: data.expires_in,
43
+ });
44
+ return {
45
+ device_code: String(data.device_code),
46
+ user_code: String(data.user_code),
47
+ verification_uri: String(data.verification_uri),
48
+ verification_uri_complete: String(data.verification_uri_complete),
49
+ expires_in: expiresIn,
50
+ interval,
51
+ verifier,
52
+ };
53
+ }
54
+ catch (error) {
55
+ debugLog("Device authorization failed", { error: String(error) });
56
+ throw new Error(`Failed to start device flow: ${error instanceof Error ? error.message : String(error)}`);
57
+ }
58
+ }
59
+ export async function pollForToken(deviceCode, codeVerifier, intervalSeconds, expiresIn) {
60
+ try {
61
+ validateDeviceCode(deviceCode);
62
+ intervalSeconds = validateInterval(intervalSeconds);
63
+ expiresIn = validateExpiresIn(expiresIn);
64
+ }
65
+ catch (error) {
66
+ debugLog("Invalid polling parameters", { error: String(error) });
67
+ return {
68
+ success: false,
69
+ error: error instanceof Error ? error.message : "Invalid parameters",
70
+ };
71
+ }
72
+ if (activePollingOperations.has(deviceCode)) {
73
+ warnLog("Polling already in progress for this device code");
74
+ return {
75
+ success: false,
76
+ error: "Authorization already in progress",
77
+ };
78
+ }
79
+ activePollingOperations.add(deviceCode);
80
+ const timeoutMs = expiresIn * 1000;
81
+ const startTime = Date.now();
82
+ let currentInterval = intervalSeconds * 1000;
83
+ let pollAttempts = 0;
84
+ const cleanup = () => activePollingOperations.delete(deviceCode);
85
+ while (Date.now() - startTime < timeoutMs) {
86
+ await new Promise((resolve) => setTimeout(resolve, currentInterval));
87
+ pollAttempts++;
88
+ const params = new URLSearchParams({
89
+ client_id: QWEN_CLIENT_ID,
90
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
91
+ device_code: deviceCode,
92
+ code_verifier: codeVerifier,
93
+ });
94
+ debugLog(`Polling attempt ${pollAttempts}...`);
95
+ try {
96
+ const response = await fetch(`${QWEN_OAUTH_BASE_URL}${QWEN_TOKEN_ENDPOINT}`, {
97
+ method: "POST",
98
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
99
+ body: params.toString(),
100
+ });
101
+ if (response.ok) {
102
+ const data = (await response.json());
103
+ infoLog("OAuth token received", {
104
+ hasAccessToken: !!data.access_token,
105
+ hasRefreshToken: !!data.refresh_token,
106
+ hasApiKey: !!data.api_key,
107
+ });
108
+ try {
109
+ validateToken(String(data.access_token));
110
+ if (data.refresh_token)
111
+ validateToken(String(data.refresh_token));
112
+ if (data.api_key)
113
+ validateToken(String(data.api_key));
114
+ const expiresIn = validateExpiresIn(typeof data.expires_in === "number" ? data.expires_in : undefined, 3600);
115
+ cleanup();
116
+ return {
117
+ success: true,
118
+ access_token: String(data.access_token),
119
+ refresh_token: data.refresh_token ? String(data.refresh_token) : undefined,
120
+ expires_in: expiresIn,
121
+ api_key: data.api_key ? String(data.api_key) : undefined,
122
+ };
123
+ }
124
+ catch (validationError) {
125
+ debugLog("Invalid token response", { error: String(validationError) });
126
+ cleanup();
127
+ return {
128
+ success: false,
129
+ error: "Received invalid token from server",
130
+ };
131
+ }
132
+ }
133
+ const errorData = await response.json().catch(() => ({}));
134
+ const oauthError = validateOAuthError(errorData);
135
+ if (oauthError.error === "authorization_pending") {
136
+ continue;
137
+ }
138
+ if (oauthError.error === "slow_down") {
139
+ currentInterval += 5000;
140
+ continue;
141
+ }
142
+ if (oauthError.error === "expired_token") {
143
+ cleanup();
144
+ return {
145
+ success: false,
146
+ error: "Device code expired. Please run '/connect' again.",
147
+ };
148
+ }
149
+ if (oauthError.error === "access_denied") {
150
+ cleanup();
151
+ return {
152
+ success: false,
153
+ error: "Authorization was denied",
154
+ };
155
+ }
156
+ cleanup();
157
+ return {
158
+ success: false,
159
+ error: oauthError.error_description || oauthError.error,
160
+ };
161
+ }
162
+ catch (error) {
163
+ debugLog("Network error during polling", { error: String(error) });
164
+ if (Date.now() - startTime >= timeoutMs) {
165
+ cleanup();
166
+ return {
167
+ success: false,
168
+ error: "Network error occurred during authentication",
169
+ };
170
+ }
171
+ }
172
+ }
173
+ cleanup();
174
+ return { success: false, error: "Polling timeout - device code expired" };
175
+ }
176
+ export async function refreshAccessToken(refreshToken) {
177
+ try {
178
+ validateToken(refreshToken);
179
+ }
180
+ catch (error) {
181
+ return { success: false, error: "Invalid refresh token" };
182
+ }
183
+ const config = getConfig();
184
+ try {
185
+ const params = new URLSearchParams({
186
+ client_id: QWEN_CLIENT_ID,
187
+ grant_type: "refresh_token",
188
+ refresh_token: refreshToken,
189
+ });
190
+ debugLog("Refreshing access token");
191
+ const response = await fetchWithRetry(`${QWEN_OAUTH_BASE_URL}${QWEN_TOKEN_ENDPOINT}`, {
192
+ method: "POST",
193
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
194
+ body: params.toString(),
195
+ }, {
196
+ maxRetries: config.maxRetries,
197
+ timeout: config.timeout,
198
+ });
199
+ if (!response.ok) {
200
+ const errorData = await response.json().catch(() => ({}));
201
+ const oauthError = validateOAuthError(errorData);
202
+ debugLog("OAuth error during token refresh", {
203
+ status: response.status,
204
+ error: oauthError.error,
205
+ });
206
+ if (oauthError.error === "invalid_grant") {
207
+ return {
208
+ success: false,
209
+ error: "Your refresh token has expired. Please run '/connect' to re-authenticate.",
210
+ };
211
+ }
212
+ if (oauthError.error === "invalid_client") {
213
+ return {
214
+ success: false,
215
+ error: "OAuth client configuration error.",
216
+ };
217
+ }
218
+ return {
219
+ success: false,
220
+ error: oauthError.error_description || oauthError.error || "Token refresh failed",
221
+ };
222
+ }
223
+ const data = (await response.json());
224
+ validateToken(String(data.access_token));
225
+ if (data.api_key)
226
+ validateToken(String(data.api_key));
227
+ const expiresIn = validateExpiresIn(typeof data.expires_in === "number" ? data.expires_in : undefined, 3600);
228
+ const newRefreshToken = data.refresh_token ? String(data.refresh_token) : refreshToken;
229
+ debugLog("Token refresh successful", {
230
+ new_refresh_token: !!data.refresh_token,
231
+ has_api_key: !!data.api_key,
232
+ });
233
+ return {
234
+ success: true,
235
+ access_token: String(data.access_token),
236
+ refresh_token: newRefreshToken,
237
+ expires_in: expiresIn,
238
+ api_key: data.api_key ? String(data.api_key) : undefined,
239
+ };
240
+ }
241
+ catch (error) {
242
+ debugLog("Token refresh failed", { error: String(error) });
243
+ return {
244
+ success: false,
245
+ error: error instanceof Error ? error.message : "Token refresh failed",
246
+ };
247
+ }
248
+ }
249
+ //# sourceMappingURL=oauth.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.strategy.js","sourceRoot":"","sources":["../../src/strategies/oauth.strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared type definitions
3
+ */
4
+ export interface OAuthAuthDetails {
5
+ type: "oauth";
6
+ refresh: string;
7
+ access: string;
8
+ expires?: number;
9
+ apiKey?: string;
10
+ }
11
+ export interface StoredCredentials {
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ expiryDate: number;
15
+ tokenType: string;
16
+ }
17
+ export interface TokenResponse {
18
+ success: boolean;
19
+ access_token?: string;
20
+ refresh_token?: string;
21
+ expires_in?: number;
22
+ api_key?: string;
23
+ error?: string;
24
+ }
25
+ export interface DeviceAuthorization {
26
+ device_code: string;
27
+ user_code: string;
28
+ verification_uri: string;
29
+ verification_uri_complete: string;
30
+ expires_in: number;
31
+ interval: number;
32
+ verifier: string;
33
+ }
34
+ export type RequestInfoType = string | URL | Request;
35
+ export interface FetchInterceptor {
36
+ (input: RequestInfoType, init?: RequestInit): Promise<Response>;
37
+ }
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACjE"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared type definitions
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Logging utilities for Qwen OAuth plugin
3
+ */
4
+ type LogLevel = "debug" | "info" | "warn" | "error";
5
+ interface LogEntry {
6
+ service: string;
7
+ level: LogLevel;
8
+ message: string;
9
+ extra?: Record<string, unknown>;
10
+ }
11
+ export declare function setLoggerClient(client: {
12
+ app: {
13
+ log: (entry: {
14
+ body: LogEntry;
15
+ }) => Promise<void>;
16
+ };
17
+ }): void;
18
+ export declare function log(level: LogLevel, message: string, data?: Record<string, unknown>): Promise<void>;
19
+ export declare const debugLog: (message: string, data?: Record<string, unknown>) => Promise<void>;
20
+ export declare const infoLog: (message: string, data?: Record<string, unknown>) => Promise<void>;
21
+ export declare const warnLog: (message: string, data?: Record<string, unknown>) => Promise<void>;
22
+ export declare const errorLog: (message: string, data?: Record<string, unknown>) => Promise<void>;
23
+ export {};
24
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAUD,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE;QAAE,GAAG,EAAE,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAE5G;AAED,wBAAsB,GAAG,CACvB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAgC,CAAC;AACzG,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAA+B,CAAC;AACvG,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAA+B,CAAC;AACvG,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAgC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Logging utilities for Qwen OAuth plugin
3
+ */
4
+ let appLogger = null;
5
+ export function setLoggerClient(client) {
6
+ appLogger = client;
7
+ }
8
+ export async function log(level, message, data) {
9
+ try {
10
+ if (appLogger) {
11
+ await appLogger.app.log({
12
+ body: {
13
+ service: "qwen-oauth",
14
+ level,
15
+ message,
16
+ extra: data,
17
+ },
18
+ });
19
+ }
20
+ else {
21
+ console.log(`[${level}] ${message}`, data || "");
22
+ }
23
+ }
24
+ catch {
25
+ console.log(`[${level}] ${message}`, data || "");
26
+ }
27
+ }
28
+ export const debugLog = (message, data) => log("debug", message, data);
29
+ export const infoLog = (message, data) => log("info", message, data);
30
+ export const warnLog = (message, data) => log("warn", message, data);
31
+ export const errorLog = (message, data) => log("error", message, data);
32
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiBH,IAAI,SAAS,GAAqB,IAAI,CAAC;AAEvC,MAAM,UAAU,eAAe,CAAC,MAAsE;IACpG,SAAS,GAAG,MAAM,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,KAAe,EACf,OAAe,EACf,IAA8B;IAE9B,IAAI,CAAC;QACH,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBACtB,IAAI,EAAE;oBACJ,OAAO,EAAE,YAAY;oBACrB,KAAK;oBACL,OAAO;oBACP,KAAK,EAAE,IAAI;iBACZ;aACF,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACzG,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACvG,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACvG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Simple mutex implementation for preventing race conditions
3
+ */
4
+ export declare class Mutex {
5
+ private locked;
6
+ private queue;
7
+ runExclusive<T>(fn: () => Promise<T>): Promise<T>;
8
+ private acquire;
9
+ private release;
10
+ isLocked(): boolean;
11
+ }
12
+ export declare class Debouncer {
13
+ private timeouts;
14
+ debounce<T extends (...args: any[]) => Promise<void>>(fn: T, delay: number): (...args: Parameters<T>) => void;
15
+ }
16
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAyB;IAEhC,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IASvD,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,OAAO;IASf,QAAQ,IAAI,OAAO;CAGpB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAuC;IAEvD,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAClD,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI;CAcpC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Simple mutex implementation for preventing race conditions
3
+ */
4
+ export class Mutex {
5
+ locked = false;
6
+ queue = [];
7
+ async runExclusive(fn) {
8
+ await this.acquire();
9
+ try {
10
+ return await fn();
11
+ }
12
+ finally {
13
+ this.release();
14
+ }
15
+ }
16
+ acquire() {
17
+ return new Promise((resolve) => {
18
+ if (!this.locked) {
19
+ this.locked = true;
20
+ resolve();
21
+ }
22
+ else {
23
+ this.queue.push(resolve);
24
+ }
25
+ });
26
+ }
27
+ release() {
28
+ const next = this.queue.shift();
29
+ if (next) {
30
+ next();
31
+ }
32
+ else {
33
+ this.locked = false;
34
+ }
35
+ }
36
+ isLocked() {
37
+ return this.locked;
38
+ }
39
+ }
40
+ export class Debouncer {
41
+ timeouts = new Map();
42
+ debounce(fn, delay) {
43
+ return (...args) => {
44
+ const timeout = this.timeouts.get(fn);
45
+ if (timeout)
46
+ clearTimeout(timeout);
47
+ this.timeouts.set(fn, setTimeout(async () => {
48
+ await fn(...args);
49
+ this.timeouts.delete(fn);
50
+ }, delay));
51
+ };
52
+ }
53
+ }
54
+ //# sourceMappingURL=mutex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,KAAK;IACR,MAAM,GAAG,KAAK,CAAC;IACf,KAAK,GAAsB,EAAE,CAAC;IAEtC,KAAK,CAAC,YAAY,CAAI,EAAoB;QACxC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,OAAO;QACb,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACnB,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,OAAO;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,EAAE,CAAC;QACT,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAED,MAAM,OAAO,SAAS;IACZ,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEvD,QAAQ,CACN,EAAK,EACL,KAAa;QAEb,OAAO,CAAC,GAAG,IAAmB,EAAE,EAAE;YAChC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,OAAO;gBAAE,YAAY,CAAC,OAAO,CAAC,CAAC;YAEnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CACf,EAAE,EACF,UAAU,CAAC,KAAK,IAAI,EAAE;gBACpB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3B,CAAC,EAAE,KAAK,CAAC,CACV,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities
3
+ */
4
+ export declare function createPkcePair(): {
5
+ verifier: string;
6
+ challenge: string;
7
+ };
8
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/utils/pkce.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAgB,cAAc,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAMxE"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities
3
+ */
4
+ import { createHash, randomBytes } from "node:crypto";
5
+ function base64UrlEncode(buffer) {
6
+ return buffer
7
+ .toString("base64")
8
+ .replace(/\+/g, "-")
9
+ .replace(/\//g, "_")
10
+ .replace(/=+$/, "");
11
+ }
12
+ export function createPkcePair() {
13
+ const verifier = base64UrlEncode(randomBytes(32));
14
+ const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
15
+ return { verifier, challenge };
16
+ }
17
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/utils/pkce.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,eAAe,CAAC,MAAc;IACrC,OAAO,MAAM;SACV,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,eAAe,CAC/B,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAC/C,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-qwen-oauth",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Qwen OAuth authentication plugin for OpenCode - authenticate with Qwen.ai using OAuth device flow",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,8 +18,8 @@
18
18
  "build": "tsc -p tsconfig.json",
19
19
  "dev": "tsc -p tsconfig.json --watch",
20
20
  "prepublishOnly": "npm run build",
21
- "test": "bun test",
22
- "test:watch": "bun test --watch",
21
+ "test": "tsx --test tests/**/*.test.ts",
22
+ "test:watch": "tsx --test --watch tests/**/*.test.ts",
23
23
  "diagnose": "npm run build && node dist/diagnostic.js",
24
24
  "test:tokens": "npm run build && node dist/token-test.js"
25
25
  },
@@ -47,6 +47,7 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^20.10.0",
50
+ "tsx": "^4.21.0",
50
51
  "typescript": "^5.3.0"
51
52
  },
52
53
  "engines": {