@iamtoricool/opencool-qwen-auth 0.0.7-alpha → 0.1.1-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -76
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/auth.d.ts +2 -62
- package/dist/lib/auth/auth.d.ts.map +1 -1
- package/dist/lib/auth/auth.js +1 -187
- package/dist/lib/auth/auth.js.map +1 -1
- package/dist/lib/constants.d.ts +6 -7
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +6 -7
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts +1 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +14 -23
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Qwen AI
|
|
3
|
-
*
|
|
4
|
-
* This plugin enables opencode to use Qwen's AI models via OAuth authentication
|
|
5
|
-
* with chat.qwen.ai, allowing users to leverage their Qwen subscription.
|
|
6
|
-
*
|
|
7
|
-
* @license MIT
|
|
2
|
+
* Qwen AI Authentication Plugin for opencode
|
|
3
|
+
* Uses Qwen's official OAuth 2.0 Device Authorization Flow
|
|
8
4
|
*/
|
|
9
5
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
10
6
|
/**
|
|
11
|
-
* Qwen AI
|
|
7
|
+
* Qwen AI Authentication Plugin
|
|
12
8
|
*/
|
|
13
9
|
export declare const QwenAuthPlugin: Plugin;
|
|
14
10
|
export default QwenAuthPlugin;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAgJ/D;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAyF5B,CAAC;AAEF,eAAe,cAAc,CAAC;AAE9B,YAAY,EACV,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,95 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Qwen AI
|
|
3
|
-
*
|
|
4
|
-
* This plugin enables opencode to use Qwen's AI models via OAuth authentication
|
|
5
|
-
* with chat.qwen.ai, allowing users to leverage their Qwen subscription.
|
|
6
|
-
*
|
|
7
|
-
* @license MIT
|
|
2
|
+
* Qwen AI Authentication Plugin for opencode
|
|
3
|
+
* Uses Qwen's official OAuth 2.0 Device Authorization Flow
|
|
8
4
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
6
|
+
import { QWEN_BASE_URL, DUMMY_API_KEY, LOG_STAGES, PLUGIN_NAME, PROVIDER_ID, QWEN_OAUTH_DEVICE_CODE_ENDPOINT, QWEN_OAUTH_TOKEN_ENDPOINT, QWEN_OAUTH_CLIENT_ID, QWEN_OAUTH_SCOPE, } from "./lib/constants.js";
|
|
11
7
|
import { loadPluginConfig, parseUserConfig, initLogger } from "./lib/config.js";
|
|
12
|
-
import { QWEN_BASE_URL, DUMMY_API_KEY, LOG_STAGES, PLUGIN_NAME, PROVIDER_ID, } from "./lib/constants.js";
|
|
13
8
|
import { logRequest, logDebug } from "./lib/logger.js";
|
|
14
|
-
import { createQwenHeaders, extractRequestUrl, handleErrorResponse, handleSuccessResponse,
|
|
9
|
+
import { createQwenHeaders, extractRequestUrl, handleErrorResponse, handleSuccessResponse, rewriteUrlForQwen, transformRequestForQwen, } from "./lib/request/fetch-helpers.js";
|
|
15
10
|
/**
|
|
16
|
-
*
|
|
11
|
+
* Generate PKCE code verifier
|
|
12
|
+
*/
|
|
13
|
+
function generateCodeVerifier() {
|
|
14
|
+
return randomBytes(32).toString("base64url").slice(0, 43);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate PKCE code challenge from verifier
|
|
18
|
+
*/
|
|
19
|
+
async function generateCodeChallenge(verifier) {
|
|
20
|
+
const encoder = new TextEncoder();
|
|
21
|
+
const data = encoder.encode(verifier);
|
|
22
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
23
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash)))
|
|
24
|
+
.replace(/\+/g, "-")
|
|
25
|
+
.replace(/\//g, "_")
|
|
26
|
+
.replace(/=/g, "");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initiate device authorization flow
|
|
30
|
+
*/
|
|
31
|
+
async function initiateDeviceAuth() {
|
|
32
|
+
const codeVerifier = generateCodeVerifier();
|
|
33
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
34
|
+
const response = await fetch(QWEN_OAUTH_DEVICE_CODE_ENDPOINT, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
38
|
+
Accept: "application/json",
|
|
39
|
+
},
|
|
40
|
+
body: new URLSearchParams({
|
|
41
|
+
client_id: QWEN_OAUTH_CLIENT_ID,
|
|
42
|
+
scope: QWEN_OAUTH_SCOPE,
|
|
43
|
+
code_challenge: codeChallenge,
|
|
44
|
+
code_challenge_method: "S256",
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const err = await response.text();
|
|
49
|
+
throw new Error(`OAuth initiation failed: ${err}`);
|
|
50
|
+
}
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
return { ...data, code_verifier: codeVerifier };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Poll for access token
|
|
56
|
+
*/
|
|
57
|
+
async function pollForToken(deviceCode, interval, maxAttempts = 120) {
|
|
58
|
+
let attempts = 0;
|
|
59
|
+
while (attempts < maxAttempts) {
|
|
60
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
61
|
+
attempts++;
|
|
62
|
+
const response = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: {
|
|
65
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
66
|
+
Accept: "application/json",
|
|
67
|
+
},
|
|
68
|
+
body: new URLSearchParams({
|
|
69
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
70
|
+
client_id: QWEN_OAUTH_CLIENT_ID,
|
|
71
|
+
device_code: deviceCode,
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
if (data.access_token) {
|
|
76
|
+
return {
|
|
77
|
+
access_token: data.access_token,
|
|
78
|
+
refresh_token: data.refresh_token,
|
|
79
|
+
expires_in: data.expires_in || 86400,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (data.error === "expired_token") {
|
|
83
|
+
throw new Error("Device code expired. Please try again.");
|
|
84
|
+
}
|
|
85
|
+
if (data.error && data.error !== "authorization_pending") {
|
|
86
|
+
throw new Error(`OAuth error: ${data.error_description || data.error}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
throw new Error("Authentication timed out. Please try again.");
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Qwen AI Authentication Plugin
|
|
17
93
|
*/
|
|
18
94
|
export const QwenAuthPlugin = async ({ client }) => {
|
|
19
95
|
const pluginConfig = loadPluginConfig();
|
|
@@ -26,21 +102,13 @@ export const QwenAuthPlugin = async ({ client }) => {
|
|
|
26
102
|
if (auth.type !== "oauth") {
|
|
27
103
|
return {};
|
|
28
104
|
}
|
|
29
|
-
|
|
30
|
-
if (!decoded) {
|
|
31
|
-
logDebug(`[${PLUGIN_NAME}] Failed to decode access token`);
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
logDebug(`[${PLUGIN_NAME}] Authenticated as:`, decoded.email || decoded.sub);
|
|
105
|
+
logDebug(`[${PLUGIN_NAME}] Using OAuth authentication`);
|
|
35
106
|
const userConfig = parseUserConfig(provider);
|
|
36
107
|
return {
|
|
37
108
|
apiKey: DUMMY_API_KEY,
|
|
38
109
|
baseURL: QWEN_BASE_URL,
|
|
39
110
|
async fetch(input, init) {
|
|
40
|
-
|
|
41
|
-
if (shouldRefreshToken(currentAuth)) {
|
|
42
|
-
currentAuth = await refreshAndUpdateToken(currentAuth, client);
|
|
43
|
-
}
|
|
111
|
+
const currentAuth = await getAuth();
|
|
44
112
|
const originalUrl = extractRequestUrl(input);
|
|
45
113
|
const url = rewriteUrlForQwen(originalUrl);
|
|
46
114
|
const originalBody = init?.body ? JSON.parse(init.body) : {};
|
|
@@ -49,13 +117,11 @@ export const QwenAuthPlugin = async ({ client }) => {
|
|
|
49
117
|
const requestInit = transformation?.updatedInit ?? init;
|
|
50
118
|
const accessToken = currentAuth.type === "oauth" ? currentAuth.access : "";
|
|
51
119
|
const headers = createQwenHeaders(requestInit, accessToken);
|
|
52
|
-
logDebug(`[${PLUGIN_NAME}]
|
|
120
|
+
logDebug(`[${PLUGIN_NAME}] Request to:`, url);
|
|
53
121
|
const response = await fetch(url, { ...requestInit, headers });
|
|
54
122
|
logRequest(LOG_STAGES.RESPONSE, {
|
|
55
123
|
status: response.status,
|
|
56
124
|
ok: response.ok,
|
|
57
|
-
statusText: response.statusText,
|
|
58
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
59
125
|
});
|
|
60
126
|
if (!response.ok) {
|
|
61
127
|
return await handleErrorResponse(response);
|
|
@@ -66,69 +132,33 @@ export const QwenAuthPlugin = async ({ client }) => {
|
|
|
66
132
|
},
|
|
67
133
|
methods: [
|
|
68
134
|
{
|
|
69
|
-
label: "
|
|
135
|
+
label: "Qwen.ai OAuth",
|
|
70
136
|
type: "oauth",
|
|
71
137
|
authorize: async () => {
|
|
72
|
-
const
|
|
73
|
-
|
|
138
|
+
const deviceAuth = await initiateDeviceAuth();
|
|
139
|
+
const fullUrl = `${deviceAuth.verification_uri}?user_code=${deviceAuth.user_code}&client=qwen-code`;
|
|
74
140
|
return {
|
|
75
|
-
url,
|
|
141
|
+
url: fullUrl,
|
|
76
142
|
method: "code",
|
|
77
|
-
instructions:
|
|
78
|
-
callback: async (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
143
|
+
instructions: `Open this URL in your browser:\n${fullUrl}\n\n1. Login with your Qwen account\n2. Wait for "Authorization Successful" message\n3. Return here and press Enter`,
|
|
144
|
+
callback: async () => {
|
|
145
|
+
try {
|
|
146
|
+
const token = await pollForToken(deviceAuth.device_code, deviceAuth.interval);
|
|
147
|
+
return {
|
|
148
|
+
type: "success",
|
|
149
|
+
access: token.access_token,
|
|
150
|
+
refresh: token.refresh_token || token.access_token,
|
|
151
|
+
expires: Date.now() + token.expires_in * 1000,
|
|
152
|
+
};
|
|
86
153
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.error(`[${PLUGIN_NAME}] Token expired`);
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error(`[${PLUGIN_NAME}] Auth failed:`, error);
|
|
90
156
|
return { type: "failed" };
|
|
91
157
|
}
|
|
92
|
-
return {
|
|
93
|
-
type: "success",
|
|
94
|
-
access: token,
|
|
95
|
-
refresh: token,
|
|
96
|
-
expires: exp ? exp * 1000 : Date.now() + 3600000,
|
|
97
|
-
};
|
|
98
158
|
},
|
|
99
159
|
};
|
|
100
160
|
},
|
|
101
161
|
},
|
|
102
|
-
{
|
|
103
|
-
label: "Auto-extract from Browser",
|
|
104
|
-
type: "oauth",
|
|
105
|
-
authorize: async () => {
|
|
106
|
-
const token = await extractBrowserSession();
|
|
107
|
-
if (token) {
|
|
108
|
-
const decoded = decodeJWT(token);
|
|
109
|
-
if (decoded) {
|
|
110
|
-
const exp = typeof decoded.exp === "number" ? decoded.exp : undefined;
|
|
111
|
-
return {
|
|
112
|
-
url: "https://chat.qwen.ai",
|
|
113
|
-
method: "code",
|
|
114
|
-
instructions: "Token extracted from browser successfully!",
|
|
115
|
-
callback: async () => ({
|
|
116
|
-
type: "success",
|
|
117
|
-
access: token,
|
|
118
|
-
refresh: token,
|
|
119
|
-
expires: exp ? exp * 1000 : Date.now() + 3600000,
|
|
120
|
-
}),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
url: "https://chat.qwen.ai",
|
|
126
|
-
method: "code",
|
|
127
|
-
instructions: "Could not extract token. Install better-sqlite3 or use 'Login with Qwen.ai' method.",
|
|
128
|
-
callback: async () => ({ type: "failed" }),
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
162
|
],
|
|
133
163
|
},
|
|
134
164
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACX,WAAW,EACX,+BAA+B,EAC/B,yBAAyB,EACzB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,gCAAgC,CAAC;AAGxC;;GAEG;AACH,SAAS,oBAAoB;IAC3B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IACnD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;SACtD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB;IAQ/B,MAAM,YAAY,GAAG,oBAAoB,EAAE,CAAC;IAC5C,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,YAAY,CAAC,CAAC;IAEhE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,+BAA+B,EAAE;QAC5D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,mCAAmC;YACnD,MAAM,EAAE,kBAAkB;SAC3B;QACD,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,SAAS,EAAE,oBAAoB;YAC/B,KAAK,EAAE,gBAAgB;YACvB,cAAc,EAAE,aAAa;YAC7B,qBAAqB,EAAE,MAAM;SAC9B,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAM/B,CAAC;IACF,OAAO,EAAE,GAAG,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,YAAY,CACzB,UAAkB,EAClB,QAAgB,EAChB,cAAsB,GAAG;IAEzB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,OAAO,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC9B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC;QACrE,QAAQ,EAAE,CAAC;QAEX,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,yBAAyB,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;gBACnD,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,8CAA8C;gBAC1D,SAAS,EAAE,oBAAoB;gBAC/B,WAAW,EAAE,UAAU;aACxB,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAM/B,CAAC;QAEF,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO;gBACL,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,KAAK;aACrC,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,uBAAuB,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAW,KAAK,EAAE,EAAE,MAAM,EAAe,EAAE,EAAE;IACtE,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;IACxC,UAAU,CAAC,YAAY,CAAC,CAAC;IAEzB,OAAO;QACL,IAAI,EAAE;YACJ,QAAQ,EAAE,WAAW;YAErB,KAAK,CAAC,MAAM,CAAC,OAA4B,EAAE,QAAiB;gBAC1D,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;gBAE7B,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC1B,OAAO,EAAE,CAAC;gBACZ,CAAC;gBAED,QAAQ,CAAC,IAAI,WAAW,8BAA8B,CAAC,CAAC;gBACxD,MAAM,UAAU,GAAe,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAEzD,OAAO;oBACL,MAAM,EAAE,aAAa;oBACrB,OAAO,EAAE,aAAa;oBAEtB,KAAK,CAAC,KAAK,CAAC,KAA6B,EAAE,IAAkB;wBAC3D,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;wBACpC,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;wBAC7C,MAAM,GAAG,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;wBAE3C,MAAM,YAAY,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;wBACvE,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,KAAK,IAAI,CAAC;wBAEjD,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;wBAC5E,MAAM,WAAW,GAAG,cAAc,EAAE,WAAW,IAAI,IAAI,CAAC;wBAExD,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC3E,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;wBAE5D,QAAQ,CAAC,IAAI,WAAW,eAAe,EAAE,GAAG,CAAC,CAAC;wBAC9C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;wBAE/D,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAE;4BAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM;4BACvB,EAAE,EAAE,QAAQ,CAAC,EAAE;yBAChB,CAAC,CAAC;wBAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;4BACjB,OAAO,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;wBAC7C,CAAC;wBAED,OAAO,MAAM,qBAAqB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;oBAC5D,CAAC;iBACF,CAAC;YACJ,CAAC;YAED,OAAO,EAAE;gBACP;oBACE,KAAK,EAAE,eAAe;oBACtB,IAAI,EAAE,OAAgB;oBACtB,SAAS,EAAE,KAAK,IAAI,EAAE;wBACpB,MAAM,UAAU,GAAG,MAAM,kBAAkB,EAAE,CAAC;wBAC9C,MAAM,OAAO,GAAG,GAAG,UAAU,CAAC,gBAAgB,cAAc,UAAU,CAAC,SAAS,mBAAmB,CAAC;wBAEpG,OAAO;4BACL,GAAG,EAAE,OAAO;4BACZ,MAAM,EAAE,MAAe;4BACvB,YAAY,EAAE,mCAAmC,OAAO,qHAAqH;4BAC7K,QAAQ,EAAE,KAAK,IAAI,EAAE;gCACnB,IAAI,CAAC;oCACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAC9B,UAAU,CAAC,WAAW,EACtB,UAAU,CAAC,QAAQ,CACpB,CAAC;oCAEF,OAAO;wCACL,IAAI,EAAE,SAAkB;wCACxB,MAAM,EAAE,KAAK,CAAC,YAAY;wCAC1B,OAAO,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY;wCAClD,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI;qCAC9C,CAAC;gCACJ,CAAC;gCAAC,OAAO,KAAK,EAAE,CAAC;oCACf,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,gBAAgB,EAAE,KAAK,CAAC,CAAC;oCACtD,OAAO,EAAE,IAAI,EAAE,QAAiB,EAAE,CAAC;gCACrC,CAAC;4BACH,CAAC;yBACF,CAAC;oBACJ,CAAC;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
package/dist/lib/auth/auth.d.ts
CHANGED
|
@@ -1,72 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth authentication
|
|
3
|
-
* Handles Google OAuth flow and JWT token extraction
|
|
2
|
+
* OAuth authentication utilities for Qwen
|
|
4
3
|
*/
|
|
5
|
-
import type {
|
|
6
|
-
/**
|
|
7
|
-
* Generate a random state value for OAuth flow
|
|
8
|
-
* @returns Random hex string
|
|
9
|
-
*/
|
|
10
|
-
export declare function createState(): string;
|
|
11
|
-
/**
|
|
12
|
-
* Parse authorization token from URL fragment
|
|
13
|
-
* Qwen returns token in format: https://chat.qwen.ai/auth#token=JWT
|
|
14
|
-
* @param url - URL with fragment containing token
|
|
15
|
-
* @returns The JWT token or undefined
|
|
16
|
-
*/
|
|
17
|
-
export declare function parseTokenFromFragment(url: string): string | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Parse authorization input from user
|
|
20
|
-
* Handles: full URL with fragment, just fragment, or just token
|
|
21
|
-
* @param input - User input
|
|
22
|
-
* @returns Parsed authorization data
|
|
23
|
-
*/
|
|
24
|
-
export declare function parseAuthorizationInput(input: string): ParsedAuthInput;
|
|
25
|
-
/**
|
|
26
|
-
* Create Google OAuth authorization flow for Qwen
|
|
27
|
-
* @returns Authorization flow details
|
|
28
|
-
*/
|
|
29
|
-
export declare function createAuthorizationFlow(): Promise<AuthorizationFlow>;
|
|
30
|
-
/**
|
|
31
|
-
* Exchange authorization code for access and refresh tokens
|
|
32
|
-
* For Qwen, the "code" is actually a JWT token obtained from URL fragment
|
|
33
|
-
* @param code - JWT token from Qwen auth
|
|
34
|
-
* @param _verifier - PKCE verifier (not used for Qwen but kept for interface)
|
|
35
|
-
* @param _redirectUri - OAuth redirect URI (not used but kept for interface)
|
|
36
|
-
* @returns Token result
|
|
37
|
-
*/
|
|
38
|
-
export declare function exchangeAuthorizationCode(code: string, _verifier?: string, _redirectUri?: string): Promise<TokenResult>;
|
|
39
|
-
/**
|
|
40
|
-
* Refresh access token using refresh token
|
|
41
|
-
* For Qwen, we just check if the token is still valid
|
|
42
|
-
* @param refreshToken - Refresh token (same as access token for Qwen)
|
|
43
|
-
* @returns Token result
|
|
44
|
-
*/
|
|
45
|
-
export declare function refreshAccessToken(refreshToken: string): Promise<TokenResult>;
|
|
4
|
+
import type { JWTPayload } from "../types.js";
|
|
46
5
|
/**
|
|
47
6
|
* Decode a JWT token to extract payload (without verification)
|
|
48
7
|
* @param token - JWT token to decode
|
|
49
8
|
* @returns Decoded payload or null if invalid
|
|
50
9
|
*/
|
|
51
10
|
export declare function decodeJWT(token: string): JWTPayload | null;
|
|
52
|
-
/**
|
|
53
|
-
* Get the Qwen OAuth login URL
|
|
54
|
-
* This is the simpler approach - open Qwen's login page directly
|
|
55
|
-
* @returns Qwen login URL
|
|
56
|
-
*/
|
|
57
|
-
export declare function getQwenLoginUrl(): string;
|
|
58
|
-
/**
|
|
59
|
-
* Build manual OAuth flow for Qwen
|
|
60
|
-
* This opens the Google OAuth directly with the Qwen callback
|
|
61
|
-
* @returns Manual OAuth flow configuration
|
|
62
|
-
*/
|
|
63
|
-
export declare function buildManualOAuthFlow(): Promise<{
|
|
64
|
-
url: string;
|
|
65
|
-
method: "code";
|
|
66
|
-
instructions: "Token not found in URL fragment";
|
|
67
|
-
callback: (input: string) => Promise<import("../types.js").TokenSuccess | {
|
|
68
|
-
type: "failed";
|
|
69
|
-
}>;
|
|
70
|
-
}>;
|
|
71
11
|
export { extractBrowserSession, isBrowserSessionAvailable, getBrowserSessionInstructions, findFirefoxCookiePath, } from "./browser-session.js";
|
|
72
12
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAc1D;AAGD,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
|
package/dist/lib/auth/auth.js
CHANGED
|
@@ -1,162 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth authentication
|
|
3
|
-
* Handles Google OAuth flow and JWT token extraction
|
|
2
|
+
* OAuth authentication utilities for Qwen
|
|
4
3
|
*/
|
|
5
|
-
import { generatePKCE } from "@openauthjs/openauth/pkce";
|
|
6
|
-
import { randomBytes } from "node:crypto";
|
|
7
|
-
import { GOOGLE_CLIENT_ID, GOOGLE_AUTHORIZE_URL, QWEN_OAUTH_LOGIN, QWEN_OAUTH_CALLBACK, GOOGLE_SCOPE, PLUGIN_NAME, ERROR_MESSAGES, } from "../constants.js";
|
|
8
|
-
/**
|
|
9
|
-
* Generate a random state value for OAuth flow
|
|
10
|
-
* @returns Random hex string
|
|
11
|
-
*/
|
|
12
|
-
export function createState() {
|
|
13
|
-
return randomBytes(16).toString("hex");
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Parse authorization token from URL fragment
|
|
17
|
-
* Qwen returns token in format: https://chat.qwen.ai/auth#token=JWT
|
|
18
|
-
* @param url - URL with fragment containing token
|
|
19
|
-
* @returns The JWT token or undefined
|
|
20
|
-
*/
|
|
21
|
-
export function parseTokenFromFragment(url) {
|
|
22
|
-
try {
|
|
23
|
-
const urlObj = new URL(url);
|
|
24
|
-
const fragment = urlObj.hash;
|
|
25
|
-
if (!fragment || !fragment.startsWith("#")) {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
// Remove leading # and parse as query string
|
|
29
|
-
const params = new URLSearchParams(fragment.substring(1));
|
|
30
|
-
return params.get("token") ?? undefined;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
// If not a valid URL, try parsing as fragment directly
|
|
34
|
-
if (url.startsWith("#")) {
|
|
35
|
-
const params = new URLSearchParams(url.substring(1));
|
|
36
|
-
return params.get("token") ?? undefined;
|
|
37
|
-
}
|
|
38
|
-
if (url.includes("token=")) {
|
|
39
|
-
const params = new URLSearchParams(url);
|
|
40
|
-
return params.get("token") ?? undefined;
|
|
41
|
-
}
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Parse authorization input from user
|
|
47
|
-
* Handles: full URL with fragment, just fragment, or just token
|
|
48
|
-
* @param input - User input
|
|
49
|
-
* @returns Parsed authorization data
|
|
50
|
-
*/
|
|
51
|
-
export function parseAuthorizationInput(input) {
|
|
52
|
-
const value = (input || "").trim();
|
|
53
|
-
if (!value)
|
|
54
|
-
return {};
|
|
55
|
-
// Try to extract token from URL fragment
|
|
56
|
-
const token = parseTokenFromFragment(value);
|
|
57
|
-
if (token) {
|
|
58
|
-
return { code: token }; // Use 'code' field for compatibility
|
|
59
|
-
}
|
|
60
|
-
// Handle direct token paste (if it looks like a JWT)
|
|
61
|
-
if (value.split(".").length === 3) {
|
|
62
|
-
return { code: value };
|
|
63
|
-
}
|
|
64
|
-
return {};
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Create Google OAuth authorization flow for Qwen
|
|
68
|
-
* @returns Authorization flow details
|
|
69
|
-
*/
|
|
70
|
-
export async function createAuthorizationFlow() {
|
|
71
|
-
const pkce = (await generatePKCE());
|
|
72
|
-
const state = createState();
|
|
73
|
-
// Build Google OAuth URL with Qwen callback
|
|
74
|
-
const url = new URL(GOOGLE_AUTHORIZE_URL);
|
|
75
|
-
url.searchParams.set("response_type", "code");
|
|
76
|
-
url.searchParams.set("client_id", GOOGLE_CLIENT_ID);
|
|
77
|
-
url.searchParams.set("redirect_uri", QWEN_OAUTH_CALLBACK);
|
|
78
|
-
url.searchParams.set("scope", GOOGLE_SCOPE);
|
|
79
|
-
url.searchParams.set("state", state);
|
|
80
|
-
url.searchParams.set("code_challenge", pkce.challenge);
|
|
81
|
-
url.searchParams.set("code_challenge_method", "S256");
|
|
82
|
-
url.searchParams.set("nonce", createState());
|
|
83
|
-
return { pkce, state, url: url.toString() };
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Exchange authorization code for access and refresh tokens
|
|
87
|
-
* For Qwen, the "code" is actually a JWT token obtained from URL fragment
|
|
88
|
-
* @param code - JWT token from Qwen auth
|
|
89
|
-
* @param _verifier - PKCE verifier (not used for Qwen but kept for interface)
|
|
90
|
-
* @param _redirectUri - OAuth redirect URI (not used but kept for interface)
|
|
91
|
-
* @returns Token result
|
|
92
|
-
*/
|
|
93
|
-
export async function exchangeAuthorizationCode(code, _verifier, _redirectUri) {
|
|
94
|
-
try {
|
|
95
|
-
// For Qwen, the "code" is actually a JWT token
|
|
96
|
-
// We verify it's a valid JWT and extract expiration
|
|
97
|
-
const decoded = decodeJWT(code);
|
|
98
|
-
if (!decoded) {
|
|
99
|
-
console.error(`[${PLUGIN_NAME}] Invalid JWT token provided`);
|
|
100
|
-
return { type: "failed" };
|
|
101
|
-
}
|
|
102
|
-
// Check token expiration
|
|
103
|
-
const exp = typeof decoded.exp === "number" ? decoded.exp : undefined;
|
|
104
|
-
const expiresIn = exp
|
|
105
|
-
? exp * 1000 - Date.now()
|
|
106
|
-
: 3600 * 1000; // Default 1 hour if no exp
|
|
107
|
-
if (expiresIn <= 0) {
|
|
108
|
-
console.error(`[${PLUGIN_NAME}] Token already expired`);
|
|
109
|
-
return { type: "failed" };
|
|
110
|
-
}
|
|
111
|
-
// For Qwen, the access token IS the JWT, and we use it as refresh too
|
|
112
|
-
return {
|
|
113
|
-
type: "success",
|
|
114
|
-
access: code,
|
|
115
|
-
refresh: code, // Qwen tokens are self-contained JWTs
|
|
116
|
-
expires: Date.now() + expiresIn,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
console.error(`[${PLUGIN_NAME}] Token exchange error:`, error);
|
|
121
|
-
return { type: "failed" };
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Refresh access token using refresh token
|
|
126
|
-
* For Qwen, we just check if the token is still valid
|
|
127
|
-
* @param refreshToken - Refresh token (same as access token for Qwen)
|
|
128
|
-
* @returns Token result
|
|
129
|
-
*/
|
|
130
|
-
export async function refreshAccessToken(refreshToken) {
|
|
131
|
-
try {
|
|
132
|
-
// Decode and check if still valid
|
|
133
|
-
const decoded = decodeJWT(refreshToken);
|
|
134
|
-
if (!decoded) {
|
|
135
|
-
console.error(`[${PLUGIN_NAME}] Invalid refresh token`);
|
|
136
|
-
return { type: "failed" };
|
|
137
|
-
}
|
|
138
|
-
// Check expiration
|
|
139
|
-
const exp = typeof decoded.exp === "number" ? decoded.exp : undefined;
|
|
140
|
-
if (exp && exp * 1000 < Date.now()) {
|
|
141
|
-
console.error(`[${PLUGIN_NAME}] Refresh token expired`);
|
|
142
|
-
return { type: "failed" };
|
|
143
|
-
}
|
|
144
|
-
// Token is still valid, return it
|
|
145
|
-
const expiresIn = exp
|
|
146
|
-
? exp * 1000 - Date.now()
|
|
147
|
-
: 3600 * 1000;
|
|
148
|
-
return {
|
|
149
|
-
type: "success",
|
|
150
|
-
access: refreshToken,
|
|
151
|
-
refresh: refreshToken,
|
|
152
|
-
expires: Date.now() + expiresIn,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
console.error(`[${PLUGIN_NAME}] Token refresh error:`, error);
|
|
157
|
-
return { type: "failed" };
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
4
|
/**
|
|
161
5
|
* Decode a JWT token to extract payload (without verification)
|
|
162
6
|
* @param token - JWT token to decode
|
|
@@ -168,7 +12,6 @@ export function decodeJWT(token) {
|
|
|
168
12
|
if (parts.length !== 3)
|
|
169
13
|
return null;
|
|
170
14
|
const payload = parts[1];
|
|
171
|
-
// Add padding if needed
|
|
172
15
|
const padding = 4 - (payload.length % 4);
|
|
173
16
|
const paddedPayload = padding === 4 ? payload : payload + "=".repeat(padding);
|
|
174
17
|
const decoded = Buffer.from(paddedPayload, "base64").toString("utf-8");
|
|
@@ -178,35 +21,6 @@ export function decodeJWT(token) {
|
|
|
178
21
|
return null;
|
|
179
22
|
}
|
|
180
23
|
}
|
|
181
|
-
/**
|
|
182
|
-
* Get the Qwen OAuth login URL
|
|
183
|
-
* This is the simpler approach - open Qwen's login page directly
|
|
184
|
-
* @returns Qwen login URL
|
|
185
|
-
*/
|
|
186
|
-
export function getQwenLoginUrl() {
|
|
187
|
-
return QWEN_OAUTH_LOGIN;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Build manual OAuth flow for Qwen
|
|
191
|
-
* This opens the Google OAuth directly with the Qwen callback
|
|
192
|
-
* @returns Manual OAuth flow configuration
|
|
193
|
-
*/
|
|
194
|
-
export async function buildManualOAuthFlow() {
|
|
195
|
-
const flow = await createAuthorizationFlow();
|
|
196
|
-
return {
|
|
197
|
-
url: flow.url,
|
|
198
|
-
method: "code",
|
|
199
|
-
instructions: ERROR_MESSAGES.TOKEN_NOT_FOUND,
|
|
200
|
-
callback: async (input) => {
|
|
201
|
-
const parsed = parseAuthorizationInput(input);
|
|
202
|
-
if (!parsed.code) {
|
|
203
|
-
return { type: "failed" };
|
|
204
|
-
}
|
|
205
|
-
const tokens = await exchangeAuthorizationCode(parsed.code);
|
|
206
|
-
return tokens?.type === "success" ? tokens : { type: "failed" };
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
24
|
// Re-export browser session functions
|
|
211
25
|
export { extractBrowserSession, isBrowserSessionAvailable, getBrowserSessionInstructions, findFirefoxCookiePath, } from "./browser-session.js";
|
|
212
26
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEpC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAE9E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,sCAAsC;AACtC,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -10,13 +10,12 @@ export declare const QWEN_BASE_URL = "https://chat.qwen.ai/api";
|
|
|
10
10
|
export declare const DUMMY_API_KEY = "qwen-oauth";
|
|
11
11
|
/** Provider ID for opencode configuration */
|
|
12
12
|
export declare const PROVIDER_ID = "qwen";
|
|
13
|
-
/** OAuth
|
|
14
|
-
export declare const
|
|
15
|
-
|
|
16
|
-
export declare const
|
|
17
|
-
export declare const
|
|
18
|
-
|
|
19
|
-
export declare const GOOGLE_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
13
|
+
/** Qwen OAuth Constants (from @opencode-qwen-auth/) */
|
|
14
|
+
export declare const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai";
|
|
15
|
+
export declare const QWEN_OAUTH_DEVICE_CODE_ENDPOINT = "https://chat.qwen.ai/api/v1/oauth2/device/code";
|
|
16
|
+
export declare const QWEN_OAUTH_TOKEN_ENDPOINT = "https://chat.qwen.ai/api/v1/oauth2/token";
|
|
17
|
+
export declare const QWEN_OAUTH_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
|
|
18
|
+
export declare const QWEN_OAUTH_SCOPE = "openid profile email model.completion";
|
|
20
19
|
/** OAuth redirect URI for local callback */
|
|
21
20
|
export declare const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
22
21
|
/** OAuth scope for Google */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,yCAAyC;AACzC,eAAO,MAAM,aAAa,6BAA6B,CAAC;AAExD,8DAA8D;AAC9D,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,6CAA6C;AAC7C,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,uDAAuD;AACvD,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,yCAAyC;AACzC,eAAO,MAAM,aAAa,6BAA6B,CAAC;AAExD,8DAA8D;AAC9D,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,6CAA6C;AAC7C,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAC1D,eAAO,MAAM,+BAA+B,mDAAqD,CAAC;AAClG,eAAO,MAAM,yBAAyB,6CAA+C,CAAC;AACtF,eAAO,MAAM,oBAAoB,qCAAqC,CAAC;AACvE,eAAO,MAAM,gBAAgB,0CAA0C,CAAC;AAExE,4CAA4C;AAC5C,eAAO,MAAM,YAAY,wCAAwC,CAAC;AAElE,6BAA6B;AAC7B,eAAO,MAAM,YAAY,yBAAyB,CAAC;AAEnD,wBAAwB;AACxB,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAEX,4BAA4B;AAC5B,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,wBAAwB;AACxB,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,qBAAqB;AACrB,eAAO,MAAM,cAAc;;;;;;;;CAQjB,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,gBAAgB;;;;CAInB,CAAC;AAEX,iCAAiC;AACjC,eAAO,MAAM,WAAW;;;;;;CAQd,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAiCxC,CAAC;AAGX,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/lib/constants.js
CHANGED
|
@@ -10,13 +10,12 @@ export const QWEN_BASE_URL = "https://chat.qwen.ai/api";
|
|
|
10
10
|
export const DUMMY_API_KEY = "qwen-oauth";
|
|
11
11
|
/** Provider ID for opencode configuration */
|
|
12
12
|
export const PROVIDER_ID = "qwen";
|
|
13
|
-
/** OAuth
|
|
14
|
-
export const
|
|
15
|
-
|
|
16
|
-
export const
|
|
17
|
-
export const
|
|
18
|
-
|
|
19
|
-
export const GOOGLE_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
13
|
+
/** Qwen OAuth Constants (from @opencode-qwen-auth/) */
|
|
14
|
+
export const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai";
|
|
15
|
+
export const QWEN_OAUTH_DEVICE_CODE_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/device/code`;
|
|
16
|
+
export const QWEN_OAUTH_TOKEN_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/token`;
|
|
17
|
+
export const QWEN_OAUTH_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
|
|
18
|
+
export const QWEN_OAUTH_SCOPE = "openid profile email model.completion";
|
|
20
19
|
/** OAuth redirect URI for local callback */
|
|
21
20
|
export const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
22
21
|
/** OAuth scope for Google */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAExD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC;AAE1C,6CAA6C;AAC7C,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAElC,uDAAuD;AACvD,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ export declare function shouldRefreshToken(auth: Auth): boolean;
|
|
|
17
17
|
* @param client - Opencode client for updating stored credentials
|
|
18
18
|
* @returns Updated auth (throws on failure)
|
|
19
19
|
*/
|
|
20
|
-
export declare function refreshAndUpdateToken(currentAuth: Auth,
|
|
20
|
+
export declare function refreshAndUpdateToken(currentAuth: Auth, _client: OpencodeClient): Promise<Auth>;
|
|
21
21
|
/**
|
|
22
22
|
* Extracts URL string from various request input types
|
|
23
23
|
* @param input - Request input (string, URL, or Request object)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-helpers.d.ts","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW3D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,IAAI,EACjB,
|
|
1
|
+
{"version":3,"file":"fetch-helpers.d.ts","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW3D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,IAAI,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,GAAG,GAAG,MAAM,CAIvE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBrD;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,GAAG,SAAS,CAAC,CA2CtE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAClB,OAAO,CAsBT;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CAkBnB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC,QAAQ,CAAC,CAcnB"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Helper functions for the custom fetch implementation
|
|
3
3
|
* These functions break down the complex fetch logic into manageable, testable units
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { decodeJWT } from "../auth/auth.js";
|
|
6
6
|
import { logRequest, logDebug } from "../logger.js";
|
|
7
7
|
import { transformRequestBody, normalizeModel } from "./request-transformer.js";
|
|
8
8
|
import { convertSseToJson, ensureContentType } from "./response-handler.js";
|
|
@@ -21,29 +21,20 @@ export function shouldRefreshToken(auth) {
|
|
|
21
21
|
* @param client - Opencode client for updating stored credentials
|
|
22
22
|
* @returns Updated auth (throws on failure)
|
|
23
23
|
*/
|
|
24
|
-
export async function refreshAndUpdateToken(currentAuth,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
export async function refreshAndUpdateToken(currentAuth, _client) {
|
|
25
|
+
// Qwen tokens are JWTs - check if still valid
|
|
26
|
+
if (currentAuth.type === "oauth" && currentAuth.access) {
|
|
27
|
+
const decoded = decodeJWT(currentAuth.access);
|
|
28
|
+
if (decoded?.exp && typeof decoded.exp === "number") {
|
|
29
|
+
const expiresAt = decoded.exp * 1000;
|
|
30
|
+
if (expiresAt > Date.now()) {
|
|
31
|
+
// Token still valid, update expires
|
|
32
|
+
currentAuth.expires = expiresAt;
|
|
33
|
+
return currentAuth;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
await client.auth.set({
|
|
32
|
-
path: { id: "qwen" },
|
|
33
|
-
body: {
|
|
34
|
-
type: "oauth",
|
|
35
|
-
access: refreshResult.access,
|
|
36
|
-
refresh: refreshResult.refresh,
|
|
37
|
-
expires: refreshResult.expires,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
// Update current auth reference if it's OAuth type
|
|
41
|
-
if (currentAuth.type === "oauth") {
|
|
42
|
-
currentAuth.access = refreshResult.access;
|
|
43
|
-
currentAuth.refresh = refreshResult.refresh;
|
|
44
|
-
currentAuth.expires = refreshResult.expires;
|
|
45
|
-
}
|
|
46
|
-
return currentAuth;
|
|
37
|
+
throw new Error(ERROR_MESSAGES.TOKEN_REFRESH_FAILED);
|
|
47
38
|
}
|
|
48
39
|
/**
|
|
49
40
|
* Extracts URL string from various request input types
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-helpers.js","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fetch-helpers.js","sourceRoot":"","sources":["../../../lib/request/fetch-helpers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamtoricool/opencool-qwen-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1-alpha",
|
|
4
4
|
"description": "Qwen AI OAuth Authentication Plugin for opencode - Access Qwen models via chat.qwen.ai subscription",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|